Damian Conway の優れたRegexp::Debuggerを使用して、次のことを試しました。
perl -MRegexp::Debugger -E '$_ = "a"; s/a*/e/g; say'
そして、イベントログモードで示されている、物事をより明確にする場合に備えて、この出力を取得しました。置換を実行する最初のパスの一致により、次の一連のイベントが生成されます。
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
これは、「a」が最初に一致し、「e」に置き換えられることを示しています。
1 回目のマッチが完了した後、デバッガーは同じプログラムから 2 回目のマッチを実行させてくれます。
| <~~ | 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
これは、元の "a" (現在は "e") の後の "" が 2 回目に一致し、"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
いずれにせよ、Perl が 3 回目のマッチングを行い、なんらかの理由で今回は置き換えを行わないことにしたか、または Regexp::Debugger か、単に混乱しているだけかのどちらかです。
編集: perldoc perlreを確認して混乱を解決しました:
「より高いレベルのループは、反復間の追加の状態を保持します: 最後の一致が長さ 0 であったかどうか。ループを壊すために、長さ 0 の一致の後の次の一致は長さ 0 を持つことが禁止されています。この禁止はバックトラッキングと相互作用します(「バックトラッキング」を参照)、最適な一致の長さがゼロの場合は、2 番目に最適な一致が選択されます。"