一天中的好时光!我正在读一本关于Perl的书: Larry Wall,Tom Christiansen,Jon Orwant写的"Programming Perl“。在这本书中,我发现了几个作者没有澄清的例子(或者只是我不明白)。
第一个
此命令仅打印hi一次。
"adfsfloglig"=~ /.*(?{print "hi"})f/;但这会打印两次"hi“??怎么解释呢?
"adfsfloglig"=~ /.*(?{print "hi"})log/;而继续体验会让事情变得更糟:
"adfsfloglig"=~ /.*(?{print "hi"})sflog/;上面的代码串只打印了一次可怕的"hi“!大约一周后,我完全明白了一件事--我需要帮助:)所以我请求你的帮助。
第二个(这是一个炸弹!)
$_ = "lothiernbfj";
m/ (?{$i = 0; print "setting i to 0\n"})
(.(?{ local $i = $i + 1; print "\ti is $i"; print "\tWas founded $&\n" }))*
(?{print "\nchecking rollback\n"})
er
(?{ $result = $i; print "\nsetting result\n"})
/x;
print "final $result\n";在这里,最终在屏幕上打印的$result等于.*匹配的字符数,但我没有再次得到它。
当打开调试打印(如上所示)时,我看到,每当新字符包含在$& (字符串的匹配部分)中时,$i就会递增。
最后$i等于11 (字符串中的字符数),然后有7次回滚,当.*一次(7次)从它的匹配字符返回时,就会发生所有模式的匹配。
但是,该死的魔术,结果被设置为$i的值!并且我们没有在任何地方递减这个值!所以$result应该等于11!但事实并非如此。作者是对的。我知道呀。
你能解释一下我很高兴见到的这个奇怪的perl代码吗?感谢您的回复!
发布于 2013-07-20 19:37:48
来自http://perldoc.perl.org/perlre.html的文档:
“警告:这个扩展的正则表达式功能被认为是实验性的,可能会在没有通知的情况下改变。由于正则表达式引擎中未来优化的影响,执行的具有副作用的代码可能在不同版本之间执行不同。这个功能的实现在5.18.0版本中进行了彻底的修改,它在早期版本中的行为要糟糕得多,特别是在解析、词法变量、作用域、递归和重入方面。
即使在匹配失败的情况下,如果regex引擎到了必须运行代码的地步,它也会运行代码。如果代码只涉及赋值给(local?)变量和任何允许的操作,回溯将导致它撤消这些操作,因此失败的匹配将不起作用。但是print操作是不能撤消的,其结果是您可以从失败的匹配中打印字符串。这就是为什么文档警告不要嵌入具有“副作用”的代码。
发布于 2013-07-20 18:52:15
我做了一些实验,并将答案制作成一个社区维基,希望人们能对其进行推广。我试图破解最简单的正则表达式,但不敢处理“炸弹”。
1. "adfsfloglig"=~ /.*(?{print "hi"})f/;
下面是regexp的调试信息:
Final program:
1: STAR (3)
2: REG_ANY (0)
3: EVAL (5)
5: EXACT <f> (7)
7: END (0)以及我的评论中的执行痕迹:
#matches the whole string with .*
0 <> <adfsflogli> | 1:STAR(3)
REG_ANY can match 11 times out of 2147483647...
#splits the string to <adfs> and <floglig> and prints "hi".
#Why does it split? Not sure, probably, knows about the f after "hi" code
4 <adfs> <floglig> | 3: EVAL(5)
#tries to find f in 'floglig' - success
4 <adfs> <floglig> | 5: EXACT <f>(7)
#end
5 <adfsf> <loglig> | 7: END(0)2. "adfsfloglig“=~ /.*(?{print "hi"})log/;
1: STAR (3)
2: REG_ANY (0)
3: EVAL (5)
5: EXACT <log> (7)
7: END (0)跟踪:
#matches the whole string with .*
0 <> <adfsflogli> | 1:STAR(3)
REG_ANY can match 11 times out of 2147483647...
#splits the string to <adfsflog> and <lig> and prints "hi".
#Probably, it found 'l' symbol after the code block
#and, being greedy, tries to capture up to the last 'l'
8 <adfsflog> <lig> | 3: EVAL(5)
#compares the 'lig' with 'log' - failed
8 <adfsflog> <lig> | 5: EXACT <log>(7)
failed...
#moves backwards, taking the previous 'l'
#prints 2-nd 'hi'
5 <adfsf> <loglig> | 3: EVAL(5)
#compares 'loglig' with 'log' - success
5 <adfsf> <loglig> | 5: EXACT <log>(7)
#end
8 <adfsflog> <lig> | 7: END(0)3. "adfsfloglig"=~ /.*(?{print "hi"})sflog/;
1: STAR (3)
2: REG_ANY (0)
3: EVAL (5)
5: EXACT <sflog> (8)
8: END (0)跟踪:
#matches the whole string with .*
0 <> <adfsflogli> | 1:STAR(3)
REG_ANY can match 11 times out of 2147483647...
#splits the string to <adf> and <sfloglig> and prints "hi".
3 <adf> <sfloglig> | 3: EVAL(5)
#compares 'sfloglig' with 'sflog' - success
3 <adf> <sfloglig> | 5: EXACT <sflog>(8)
#end
8 <adfsflog> <lig> | 8: END(0)https://stackoverflow.com/questions/17760103
复制相似问题