gregorian
正则匹配的问题
$digits="1234567890";
@aa=$digits=~/(?=(/d/d/d))/g;
@aa 的结果是 123 234 345 456 567 678 789 890
没有明白这里面的匹配过程 ,希望有知道的能说说 为什么会是这个结果。
zhasm
对于代码:
[table=95%][tr][td][font=FixedSys][color=#000000][color=#0000FF]@[/color][color=#808000]aa[/color][color=#0000CC]=[/color][color=#0000FF]$[/color][color=#008080]digits[/color][color=#0000CC]=[/color][color=#0000CC]~[/color][color=#0000CC]/[/color][color=#0000CC]([/color][color=#0000CC]?[/color][color=#0000CC]=[/color][color=#0000CC]([/color][color=#0000CC]/[/color]d/d/d[color=#0000CC])[/color][color=#0000CC])[/color][color=#0000CC]/[/color]g[color=#0000CC];[/color][/color][/font][/td][/tr][/table]
,它尝试匹配的是任意三位连续的数字。但是由于是全局匹配,而且使用过的字符还可以重复使用,因此出现了这样的结果:
[table=95%][tr][td][font=FixedSys]123 234 345 456 567 678 789 890[/font][/td][/tr][/table]
如果楼主是要每三位之间分开,不重复使用字符,可以使用这样的表达式:
[table=95%][tr][td][font=FixedSys][color=#000000][color=#0000FF]@[/color][color=#808000]aa[/color][color=#0000CC]=[/color][color=#0000FF]$[/color][color=#008080]digits[/color][color=#0000CC]=[/color][color=#0000CC]~[/color][color=#0000CC]/[/color][color=#0000CC]([/color][color=#0000CC]?[/color][color=#0000CC]>[/color][color=#0000CC]([/color][color=#0000CC]/[/color]d/d/d[color=#0000CC])[/color][color=#0000CC])[/color][color=#0000CC]/[/color]g[color=#0000CC];[/color][/color][/font][/td][/tr][/table]
其结果将是:
[table=95%][tr][td][font=FixedSys]123 456 789[/font][/td][/tr][/table]
这是因为,固化分组[color=Magenta][b]?>[/b][/color]使得用过的字符不再参与下一次的匹配。
zhasm
如果想实现
[table=95%][tr][td][font=FixedSys]123 345 567 789[/font][/td][/tr][/table]
可以使用下面的代码:
[table=95%][tr][td][font=FixedSys][color=#000000][color=#0000FF]while[/color][color=#0000CC]([/color][color=#0000FF]$[/color][color=#008080]digits[/color] [color=#0000CC]=[/color][color=#0000CC]~[/color] s[color=#0000CC]/[/color][color=#0000CC]([/color][color=#0000CC]/[/color]d/d[color=#0000CC])[/color][color=#0000CC]([/color][color=#0000CC]/[/color]d[color=#0000CC])[/color][color=#0000CC]/[/color][color=#0000CC]/[/color]2[color=#0000CC]/[/color][color=#0000CC])[/color]
[color=#0000CC]{[/color]
[color=#FF0000]print[/color] [color=#0000FF]$[/color][color=#008080]1[/color][color=#0000CC].[/color][color=#0000FF]$[/color][color=#008080]2[/color][color=#0000CC],[/color][color=#FF00FF]"/n"[/color][color=#0000CC];[/color]
[color=#0000CC]}[/color][/color][/font][/td][/tr][/table]
churchmice
回复 #5 gregorian 的帖子
你需要明白/g的作用,以及?=是干什么的
这样说吧,?=匹配的是一个位置
对于你的情况
[code]
@aa=$digits=~/(?=(/d/d/d))/g;
[/code]
正则引擎从字符串的第0个位置开始,匹配的是这样一个位置:后面是三个数字并且将结果捕获。
很显然第0个位置已经满足这个要求,所以匹配是满足的,返回结果123到@a中
这个时候你需要注意了,由于这个位置(位置0)可以匹配无限次,这个和一般的匹配,比如说/d /s是不一样的,这些匹配时消耗字符串的,而?=是不消耗字符串的,由于能够匹配无限多次(由于/g的作用),那势必引起死循环,所以这个时候正则引擎就会帮你跳出死循环,具体的表现就是它会帮你移动匹配的位置,从第0位置移动到第1个位置,依次类推,所以会出现你这样的情况。
churchmice
具体的你可以通过下面这个脚本来看匹配过程
[code]
#!/usr/bin/perl
use strict;
use warnings;
my $digit = "12345678";
my @aa = $digit =~ /(?{print "Staring match at $`|$'/n"})(?=(/d/d/d))/g
[/code]
结果是
[quote]
Staring match at |12345678
Staring match at |12345678
Staring match at 1|2345678
Staring match at 1|2345678
Staring match at 12|345678
Staring match at 12|345678
Staring match at 123|45678
Staring match at 123|45678
Staring match at 1234|5678
Staring match at 1234|5678
Staring match at 12345|678
Staring match at 12345|678
Staring match at 123456|78
Staring match at 1234567|8
Staring match at 12345678
[/quote]
注意有些行的结果是一样的,这是因为上面所说的?=是不消耗字符串的,如果正则引擎没有帮忙(术语叫regex tranmission bump along),那么同样的行会出现无限次,这就是死循环,我个人的理解是这样的,正则引擎看到两次匹配的起始位置都是同一个并且匹配的都是同一个结果时,它就认为程序已经在死循环了,所以会帮你bump along.
类似的还有
[code]
?=
?!
?<=
?<!
[/code]
其中后面两个的表达式不能包含*,+等不定数量描述符
前面两个没有这样的限制