正则匹配的问题

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]使得用过的字符不再参与下一次的匹配。

gregorian
谢谢  不过我还是没有搞明白
@aa=$digits=~/(/d/d/d)/g;
出现的是 123 456 789
这个?=是什么模式  我试过用??=结果说错误
?=是什么 你后面说道?>又是什么
如果我要实现的是
123 345 567 789呢

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]

gregorian
谢谢 zhasm
不过我更想要的是这个正则的思路,和你是怎么想的。而不仅仅是一个答案。
能说说 ?= ?> 这些都代表什么东西

redicaps
?=这个玩意中文翻译叫做零宽度断言
作用是匹配的时候正则表达式引擎不向前移动
而如果全部正则表达式都是零宽度的,就像你给的例子,会出现保持在第一个位置不动而无限循环的情况,所以此时正则引擎会自动前移一个字符位置来避免这种情况。

其他的?扩展模式见perldoc perlre

gregorian
谢谢 redicaps
有的明白你的意思了
perldoc perlre还真好用

不死草
呵呵,正则式果然博大精深。。。:em17:

小公猫
学习了~
没用过这么有难度的~

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]
其中后面两个的表达式不能包含*,+等不定数量描述符
前面两个没有这样的限制

mouse.rice
学习下perl的[color=Red][b]lookaround[/b][/color]用法,即”[color=Red][b]环视[/b][/color]“用法!看半个钟头书一切就明白了...