默认情况下,Python 和 sed 都是贪婪的,但是...... Python 正则表达式尝试在所有情况下从左到右进行评估,尽管如果正在尝试的分支无法通过匹配继续,它最终必须回溯到先前的状态。相反,Sed 正则表达式在评估之前进行优化,以防止不必要的回溯,通过将正则表达式重写为更具确定性的形式。因此,组合的可选模式“aab”可能在普通的“a”之前测试,因为最具体的可能字符串首先被尝试。
Python 模式将字符串“aabb”匹配为“aab”+“b”两次(标记在“<>”之间)
>>> re.sub("a*((ab)*)b", r"<\1>", "aabb")
'<><>'
而 sed 通过一个替换匹配整个“aabb”:
$ echo "aabb" | sed "s/a*\(\(ab\)*\)b/<\1>/"
<ab>
Python regex backtrace 算法在regex howto - Repeating Things in two paragraphs 由“A step-by-step example...”一词介绍的很好地解释了。它完全按照正则表达式文档的描述执行 IMO :“扫描目标字符串时,RE 由 '|' 分隔 从左到右尝试。”
示范
顺便说一句,“(|a|aa)”的顺序。"(aa|a|)" 受到 Python 的尊重
>>> re.sub("(?:|a|aa)((ab)*)b", r"<\1>", "aabb")
'<ab>'
>>> re.sub("(?:aa|a|)((ab)*)b", r"<\1>", "aabb")
'<><>'
但是这个顺序被sed 忽略了,因为 sed 优化了正则表达式。匹配“aab”+“b”可以从模式中删除“a”选项来复制。
$ echo "aabb" | sed "s/\(\|a\|aa\)\(\(ab\)*\)b/<\2>/g"
<ab>
$ echo "aabb" | sed "s/\(aa\|a\|\)\(\(ab\)*\)b/<\2>/g"
<ab>
$ echo "aabb" | sed "s/\(aa\|\)\(\(ab\)*\)b/<\2>/g"
<><>
编辑:我删除了有关 DFA/NFA 的所有内容,因为我无法从当前文本中证明这一点。