首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >误解perl regexp求值

误解perl regexp求值
EN

Stack Overflow用户
提问于 2013-07-20 15:56:02
回答 2查看 230关注 0票数 7

一天中的好时光!我正在读一本关于Perl的书: Larry Wall,Tom Christiansen,Jon Orwant写的"Programming Perl“。在这本书中,我发现了几个作者没有澄清的例子(或者只是我不明白)。

第一个

此命令仅打印hi一次。

代码语言:javascript
运行
复制
 "adfsfloglig"=~ /.*(?{print "hi"})f/;

但这会打印两次"hi“??怎么解释呢?

代码语言:javascript
运行
复制
 "adfsfloglig"=~ /.*(?{print "hi"})log/;

而继续体验会让事情变得更糟:

代码语言:javascript
运行
复制
  "adfsfloglig"=~ /.*(?{print "hi"})sflog/;

上面的代码串只打印了一次可怕的"hi“!大约一周后,我完全明白了一件事--我需要帮助:)所以我请求你的帮助。

第二个(这是一个炸弹!)

代码语言:javascript
运行
复制
 $_ = "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代码吗?感谢您的回复!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-07-20 19:37:48

来自http://perldoc.perl.org/perlre.html的文档:

“警告:这个扩展的正则表达式功能被认为是实验性的,可能会在没有通知的情况下改变。由于正则表达式引擎中未来优化的影响,执行的具有副作用的代码可能在不同版本之间执行不同。这个功能的实现在5.18.0版本中进行了彻底的修改,它在早期版本中的行为要糟糕得多,特别是在解析、词法变量、作用域、递归和重入方面。

即使在匹配失败的情况下,如果regex引擎到了必须运行代码的地步,它也会运行代码。如果代码只涉及赋值给(local?)变量和任何允许的操作,回溯将导致它撤消这些操作,因此失败的匹配将不起作用。但是print操作是不能撤消的,其结果是您可以从失败的匹配中打印字符串。这就是为什么文档警告不要嵌入具有“副作用”的代码。

票数 6
EN

Stack Overflow用户

发布于 2013-07-20 18:52:15

我做了一些实验,并将答案制作成一个社区维基,希望人们能对其进行推广。我试图破解最简单的正则表达式,但不敢处理“炸弹”。

1. "adfsfloglig"=~ /.*(?{print "hi"})f/;

下面是regexp的调试信息:

代码语言:javascript
运行
复制
Final program:
   1: STAR (3)
   2:   REG_ANY (0)
   3: EVAL (5)
   5: EXACT <f> (7)
   7: END (0)

以及我的评论中的执行痕迹:

代码语言:javascript
运行
复制
#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/;

代码语言:javascript
运行
复制
 1: STAR (3)
 2:   REG_ANY (0)
 3: EVAL (5)
 5: EXACT <log> (7)
 7: END (0)

跟踪:

代码语言:javascript
运行
复制
#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/;

代码语言:javascript
运行
复制
 1: STAR (3)
 2:   REG_ANY (0)
 3: EVAL (5)
 5: EXACT <sflog> (8)
8: END (0)

跟踪:

代码语言:javascript
运行
复制
#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)
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17760103

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档