Python と sed はどちらもデフォルトで貪欲ですが... Python 正規表現は、試行されているブランチが一致して続行できない場合、最終的に前の状態に戻る必要があるにもかかわらず、すべての状況で左から右に評価しようとします。反対に、Sed 正規表現は、正規表現をより決定論的な形式に書き換えることにより、不要なバックトレースを防ぐために評価前に最適化されます。したがって、結合されたオプションのパターン "aab" は、最も具体的な可能な文字列が最初に試行されるため、通常の "a" よりも前にテストされる可能性があります。
Python パターンは、文字列 "aabb" を "aab" + "b" ("<>" で囲まれている) として 2 回一致させます。
>>> re.sub("a*((ab)*)b", r"<\1>", "aabb")
'<><>'
一方、sed は「aabb」全体を 1 つの置換で一致させます。
$ echo "aabb" | sed "s/a*\(\(ab\)*\)b/<\1>/"
<ab>
Python 正規表現バックトレース アルゴリズムは、正規表現のハウツーで説明されています。「ステップバイステップの例...」という言葉で紹介されている 2 つの段落で物事を繰り返します。正規表現ドキュメントで説明されているとおりに 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 に関するすべてを削除しました。