一天的好时光!我正在读一本关于perl的书:"编程Perl"由Larry Wall,Tom Christiansen,Jon Orwant撰写.在这本书中,我发现了一些作者没有澄清的例子(或者我当时没有得到).
这仅打印ONCE.
"adfsfloglig"=~ /.*(?{print "hi"})f/;
Run Code Online (Sandbox Code Playgroud)
但这打印"嗨"TWICE ?? 怎么解释?
"adfsfloglig"=~ /.*(?{print "hi"})log/;
Run Code Online (Sandbox Code Playgroud)
继续经历甚至使事情变得更糟:
"adfsfloglig"=~ /.*(?{print "hi"})sflog/;
Run Code Online (Sandbox Code Playgroud)
上面的代码串再次打印ONCE这个可怕的"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";
Run Code Online (Sandbox Code Playgroud)
在这里,$result屏幕上的最终打印等于匹配的字符数.*,但我不再重复.
当打开调试打印(如上所示)时,我看到,$i每当新的字符包含在$&(字符串的匹配部分)中时,它就会递增.
最后$i等于11(字符串中的字符数量),然后有7次回滚,当.*从其匹配字符一次返回时(7次),因此发生所有模式的匹配.
但是,该死的魔法,结果是设定值$i!我们并没有在任何地方减少这个价值!所以$result应该等于11!但事实并非如此.作者是对的.我知道.
拜托,你能解释一下这个奇怪的perl代码,我很高兴见到了吗?谢谢你的回答!
来自http://perldoc.perl.org/perlre.html上的文档:
"警告:这种扩展的正则表达式功能被认为是实验性的,并且可能会在没有通知的情况下进行更改.由于正则表达式引擎中未来优化的影响,具有副作用的代码在版本之间可能无法完全相同.此功能的实现对于5.18.0版本进行了彻底检查,并且它在早期版本的perl中的行为更加困难,特别是在解析,词汇变量,范围,递归和重入方面."
即使在失败的匹配中,如果正则表达式引擎到达必须运行代码的点,它也将运行代码.如果代码仅涉及分配给(本地?)变量以及允许的任何操作,则回溯将导致它撤消操作,因此失败的匹配将不起作用.但print操作无法撤消,结果是您可以从失败的匹配中打印字符串.这就是为什么文档警告不要嵌入带有"副作用"的代码.
我做了一些实验,并将答案作为社区维基,希望人们能够填充它.我试图破解最简单的正则表达式并且不敢处理"炸弹".
这是regexp的调试信息:
Final program:
1: STAR (3)
2: REG_ANY (0)
3: EVAL (5)
5: EXACT <f> (7)
7: END (0)
Run Code Online (Sandbox Code Playgroud)
以及我的评论执行的痕迹:
#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)
Run Code Online (Sandbox Code Playgroud)
1: STAR (3)
2: REG_ANY (0)
3: EVAL (5)
5: EXACT <log> (7)
7: END (0)
Run Code Online (Sandbox Code Playgroud)
跟踪:
#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)
Run Code Online (Sandbox Code Playgroud)
1: STAR (3)
2: REG_ANY (0)
3: EVAL (5)
5: EXACT <sflog> (8)
8: END (0)
Run Code Online (Sandbox Code Playgroud)
跟踪:
#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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
207 次 |
| 最近记录: |