Kleene的明星:为什么$ _ ="a"; s/a*/e/g产生:ee

Lit*_*rat 31 regex perl

a* 意味着零个或多个实例:权利?

那么为什么会$_ = "a"; s/a*/e/g产生:ee

可能的答案:它正在替换字符串:"a"with:"e",它正在替换空字符串:""with:"e".或者它正在取代仅仅缺少一封信:a带有一封信:e或它取代了"零次出现":a与:e

好的,但是:

$_ = "b"; s/a*/e/g 生产: ebe

这似乎是在更换空字符串左:b空字符串的权利:b

好.但那为什么不这样做:" a"?为什么它不更换空字符串的左:a空字符串的右侧:和的信:一个本身得到:eee

有几个零次出现:a左侧是右侧!

DVK*_*DVK 27

您分析结果为何"ee""ebe"完全准确的原因.

"/ g"修饰符使正则表达式匹配一次,然后尝试再次匹配上次匹配停止的位置.

差异的原因(它不会替换左边的空字符串"a")是因为它"*"贪婪的 - 它匹配最可能的字符.来自perldoc perlre:

默认情况下,量化的子模式是"贪婪的",也就是说,它将尽可能多地匹配(给定一个特定的起始位置),同时仍然允许模式的其余部分匹配.

所以它匹配零"a",并看它是否可以匹配更多.由于字符串中有更多的"a",它将再匹配一个.尝试匹配更多.没有?完成.所以我们匹配第一个"a".

那么,"/ G"使我们再次尝试匹配(从这里我们就完成了最后一场比赛后停止启动,它现在匹配空(零"一个" S)的字符串).


zos*_*tay 19

使用Damian Conway优秀的Regexp :: Debugger,我尝试了这个:

perl -MRegexp::Debugger -E '$_ = "a"; s/a*/e/g; say'
Run Code Online (Sandbox Code Playgroud)

并且在事件记录模式下显示了这个输出,以防它变得更清晰.通过替换的第一次传递匹配产生这组事件:

a               | a*              |   Starting regex match
a               | a*              |     Trying a literal character zero-or-more times (as many as possible)
                | a*              |     Matched
                |                 |   Regex matched in 3 steps
Run Code Online (Sandbox Code Playgroud)

这表明"a"在第一次匹配时被"e"取代.

在第一次完成匹配后,调试器允许我从同一程序运行第二次匹配:

                | <~~             |   Back-tracking in regex
                | a*              |   Back-tracked and restarting regex match
                | a*              |     Trying a literal character zero-or-more times (as many as possible)
                | a*              |     Matched
                |                 |   Regex matched in 3 steps
Run Code Online (Sandbox Code Playgroud)

这表明原始"a"(现在为"e")之后的""与第二次匹配并用"e"代替.

不幸的是,要么我不知道如何读取输出,要么Regexp :: Debugger在这一点或其他什么时候会混淆,但它会再次重复,但不会替换.

                | <~~             |   Back-tracking in regex
                | a*              |   Back-tracked and restarting regex match
                | a*              |     Trying a literal character zero-or-more times (as many as possible)
                | a*              |     Matched
                |                 |   Regex matched in 3 steps
Run Code Online (Sandbox Code Playgroud)

总之,无论是Perl已经相匹配的第三次决定的原因并没有做更换这段时间或正则表达式::调试器或我只是困惑.

编辑:我通过审查perldoc perlre解决了我的困惑:

"更高级别的循环在迭代之间保留了一个额外的状态:最后一个匹配是否为零长度.要打破循环,禁止零长度匹配后的跟随匹配长度为零.此禁止与回溯相互作用(参见"回溯"),如果最佳匹配的长度为零,则选择第二个最佳匹配."


hob*_*bbs 8

首先,正如人们所说,a*贪婪; 如果它可以匹配"a",它将不匹配空字符串.其次,/g匹配将尽可能多地匹配,但它不会在同一位置连续两次进行零长度匹配.因为这意味着模式没有进展.如果可以,则强制该模式进行一些其他非零长度匹配,否则失败.

s/a*/e/g在"a"上运行时,首先a*匹配位置0处的"a"(并前进到位置1),因此"a"被替换为"e".然后a*匹配位置1处的空字符串(并且不前进),因此""替换为"e".现在我们仍然处于位置1,并且a*禁止再次匹配空字符串,并且不能再匹配任何东西,因此模式失败并且perl尝试前进到字符串中的下一个字符.但我们已达到字符串结尾,因此输出为"ee".

s/a*/e/g在"b"上运行时,首先a*匹配位置0处的空字符串(并且不前进),将""替换为"e".然后,禁止在位置0处的另一个匹配,因此模式前进到位置1(越过"b",其未被替换).然后a*匹配位置1处的空字符串,并将其替换为"e"; 并且,禁止在相同位置匹配两次,并且perl不能超出字符串的末尾,因此结果是"ebe".

最后,想象一下s/a*/e/g在"ab"上运行.a*匹配位置0的"aa",替换为"e",并前进到位置2; a*匹配位置2处的空字符串,替换为"e"并且不前进; a*无法进行非空匹配并失败; 扫描"b"; a*匹配位置3处的空字符串,替换为"e"并且不前进; 字符串的结尾.所以结果是"eebe",正如perl将证实的那样.