2016-12-06 2 views
3

fand ich, dass nicht gieriger Regex nur nicht gierig werden, wenn sie an den vorderen Verankerung, nicht bis zum Ende:Regex eines nicht-gierigen Spiel unterschiedlichen Verhalten

$ 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 

Nun Blick auf diese, wenn die Verankerung bis zum ende:

$ 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? 

warum ist das? wie kommt es nicht abc wie vorher drucken?

(Das Problem wurde in meinem Go-Code gefunden, aber zur Vereinfachung in Perl dargestellt).

+0

'/(a.c *?) $ /' Stimmt mit der letzten 'abc' in 'abcabcabc' überein. Da Sie am Ende verankern, sollte das c nicht gierig gemacht werden. –

+0

@AdityaJ., Nein, Sie haben den "Algorithmus" geändert. Für Ihre "Lösung", auch ohne '*?', D. H. '/(a.c) $ /', würde es immer noch funktionieren. Aber danke fürs ausprobieren. – xpt

+0

Mit '. *?' Beginnt die Regex-Engine mit der Mindestanzahl von Zeichen, die vom Quantifizierer erlaubt sind - was ** null ** ist. Der Motor fährt dann fort und versucht das nächste Token. Dies schlägt fehl, also rückt die Engine zurück und erweitert ihre Übereinstimmung. Der Prozess wiederholt sich selbst - die Regex-Engine rückt vor, schlägt fehl, backtracks, erweitert ihre Übereinstimmung erneut, schreitet fort, scheitert, ... dies ist ein Fall für die Negation '/ a [^ a] * c $ /' – hwnd

Antwort

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

Nicht gierig bedeutet, es werden die wenigsten Zeichen möglich an der aktuellen Position entsprechen, so dass das gesamte Muster übereinstimmt.

Nach a an Position passenden 0 ist bcabcab die am wenigsten .*? an Position entsprechen kann 1 während immer noch den Rest der Muster genügen.

"abcabcabc" = /a.*?c$/ im Detail:

  1. Bei po 0, a Matches 1 char (a).
    1. Bei Pos 1 entspricht .*? 0 Zeichen (leere Zeichenfolge).
      1. Bei Position 1 stimmt c nicht überein. Zurück!
    2. Bei Pos 1 entspricht .*? 1 Char (b).
      1. Bei Position 2 entspricht c 1 Char (c).
        1. Bei Position 3 stimmt $ nicht überein. Zurück!
    3. an Pos 1, .*? Spielen 2 Zeichen (bc).
      1. Bei Position 1 stimmt c nicht überein. Zurück!
    4. ...
    5. An Pos 1 .*? Streichhölzer 7 Zeichen (bcabcab).
      1. Bei Position 8 entspricht c 1 Char (c).
        1. Bei Position 9 entspricht $ 0 Zeichen (leere Zeichenfolge). Spiel erfolgreich!

"abcabcabc" = /a.*c$/ im Detail (für Kontrast):

  1. am POS 0, a Spiele 1 char (a).
    1. Bei Position 1 entspricht .* 8 Zeichen (abcabcabc).
      1. Bei Position 9 stimmt c nicht überein. Zurück!
    2. Bei Position 1 entspricht .* 7 Zeichen (abcabcab).
      1. Bei Position 8 entspricht c 1 Char (c).
        1. Bei Position 9 entspricht $ 0 Zeichen (leere Zeichenfolge). Spiel erfolgreich!

Tipp: Vermeiden Sie Muster mit zwei Instanzen eines nicht-greediness Modifikator. Sofern Sie sie nicht als Optimierung verwenden, besteht eine gute Chance, dass sie mit etwas übereinstimmen, das nicht mit ihnen übereinstimmen soll. Dies ist hier relevant, weil Muster implizit mit \G(?s:.*?)\K beginnen (außer sie werden durch einen führenden ^, \A oder \G aufgehoben).

Was Sie wollen, ist eine der folgenden Möglichkeiten:

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

Sie auch eine der folgenden Optionen verwenden:

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

Es wäre ineffizient und nicht lesbar sein, die letzteren drei in dieser Situation zu verwenden, , aber sie arbeiten mit Begrenzungen, die länger als ein Zeichen sind.