2016-12-06 5 views
3

は私が前にではなく、最後に固定するとき非貪欲正規表現マッチが唯一の非貪欲になることがわかった:アンカーとき正規表現

$ echo abcabcabc | perl -ne 'print $1 if /^(a.*c)/' 
abcabcabc 
# OK, greedy match 

$ echo abcabcabc | perl -ne 'print $1 if /^(a.*?c)/' 
abc 
# YES! non-greedy match 

は今、これを見て最後まで:

$ echo abcabcabc | perl -ne 'print $1 if /(a.*c)$/' 
abcabcabc 
# OK, greedy match 

$ echo abcabcabc | perl -ne 'print $1 if /(a.*?c)$/' 
abcabcabc 
# what, non-greedy become greedy? 

なぜですか?どのように印刷されませんabc以前と同じ?

(問題は私のGoコードにありますが、簡単にするためにPerlで説明しています)。

+0

'/(a.c *?)$ /'は 'abcabcabc'の最後の 'abc'と一致します。あなたが最後に固執しているので、cは非貪欲にする必要があります。 –

+0

@AdityaJ。、Nah、あなたは "アルゴリズム"を変更しました。あなたの "解決策"については、 '*?'がなくても、 '/(a.c)$ /'のように動作しても、それでも動作します。しかし、お試しいただきありがとうございます。 – xpt

+0

'。*? 'を使うと、正規表現エンジンは、量指定子で許可されている最小文字数(**ゼロ**)と一致し始めます。その後、エンジンは前進して次のトークンを試行します。これは失敗し、エンジンはそのマッチをバックトラックして展開します。プロセスは繰り返されます。正規表現エンジンは進んだり、失敗したり、逆戻りしたり、一致を再開したり、進歩したり、失敗したりします。これは否定の場合です。/ a [^ a] * c $/' – hwnd

答えて

7
$ echo abcabcabc | perl -ne 'print $1 if /(a.*?c)$/' 
abcabcabc 
# what, non-greedy become greedy? 

非貪欲それが全体のパターンが一致していることをは、現在の場所で可能最小限の文字と一致します意味。

位置0aを照合した後、bcabcabはまだパターンの残りの部分を満たしながら少なくとも.*?位置1に一致させることができています。詳細

"abcabcabc" = /a.*?c$/:POS 0で

  1. aマッチ1つのCHAR(a)。
    1. pos1の場合、.*?は0文字(空の文字列)に一致します。
      1. pos1では、cは一致しません。バックトラック!
    2. pos 1では、.*?は1文字(b)に一致します。
      1. pos2では、cは1文字(c)に一致します。
        1. pos3では、$が一致しません。バックトラック! POS 1で
    3. .*?マッチ2つの文字(bc)。
      1. pos1では、cは一致しません。バックトラック! POS 1で
    4. ...
    5. .*?試合7つの文字(bcabcab)。
      1. pos8では、cは1文字(c)に一致します。
        1. pos 9の場合、$は0文字(空文字列)と一致します。マッチ成功!(コントラスト)
        2. 詳細

"abcabcabc" = /a.*c$/:POS 0で

  1. aマッチ1つのCHAR(a)。
    1. pos1の場合、.*は8文字(abcabcabc)と一致します。
      1. pos 9では、cが一致しません。バックトラック!
    2. pos1の場合、.*は7文字(abcabcab)と一致します。
      1. pos8では、cは1文字(c)に一致します。
        1. pos 9の場合、$は0文字(空文字列)と一致します。マッチ成功!

ヒント:非貪欲修飾子の2つのインスタンスでパターンを避けてください。最適化として使用していない限り、一致させたくないものと一致する可能性があります。パターンは暗黙的に\G(?s:.*?)\Kで始まります(先頭の^\Aまたは\Gで取り消されない限り)。何をしたい

は、次のいずれかです。

/a[^a]*c$/ 
/a[^c]*c$/ 
/a[^ac]*c$/ 

あなたはまた、次のいずれかを使用することができます。

/a(?:(?!a).)c$/s 
/a(?:(?!c).)c$/s 
/a(?:(?!a|c).)c$/s 

このような状況では、これら後者の3つを使用するのは非効率と読めないだろうしかし、それらは1文字よりも長い境界で動作します。