Frage

In einigen Regex-Varianten werden [negative] Behauptungen mit der Breite Null (Look-Ahead/Look-Behind) nicht unterstützt.

Dies macht es äußerst schwierig (unmöglich?), einen Ausschluss festzustellen.Zum Beispiel „jede Zeile das nicht habe „foo“ drauf“, etwa so:

^((?!foo).)*$

Kann dasselbe erreicht werden, ohne überhaupt Look-Around zu verwenden (Komplexitäts- und Leistungsbedenken vorerst außer Acht gelassen)?

War es hilfreich?

Lösung

UPDATE: Es scheitert "mit zwei ff vor oo" als @ Ciantic wies in den Kommentaren aus.


^(f(o[^o]|[^o])|[^f])*$

Hinweis: Es ist viel viel einfacher, nur ein Spiel auf der Clientseite zu negieren, anstatt die oben Regex zu verwenden.

Die Regex geht davon aus, dass jede Zeile mit einem Newline Zeichen endet, wenn es nicht so ist C ++ 's und grep regexs sehen.

Beispielprogramme in Perl, Python, C ++, und grep alle die gleiche Leistung geben.

  • perl

    #!/usr/bin/perl -wn
    print if /^(f(o[^o]|[^o])|[^f])*$/;
    
  • Python

    #!/usr/bin/env python
    import fileinput, re, sys
    from itertools import ifilter
    
    re_not_foo = re.compile(r"^(f(o[^o]|[^o])|[^f])*$")
    for line in ifilter(re_not_foo.match, fileinput.input()):
        sys.stdout.write(line)
    
  • c ++

    #include <iostream>
    #include <string>
    #include <boost/regex.hpp>
    
    int main()
    {
      boost::regex re("^(f(o([^o]|$)|([^o]|$))|[^f])*$");
      //NOTE: "|$"s are there due to `getline()` strips newline char
    
      std::string line;
      while (std::getline(std::cin, line)) 
        if (boost::regex_match(line, re))
          std::cout << line << std::endl;
    }
    
  • grep

    $ grep "^\(f\(o\([^o]\|$\)\|\([^o]\|$\)\)\|[^f]\)*$" in.txt
    

Beispieldatei:

foo
'foo'
abdfoode
abdfode
abdfde
abcde
f

fo
foo
fooo
ofooa
ofo
ofoo

Ausgabe:

abdfode
abdfde
abcde
f

fo
ofo

Andere Tipps

Bin auf diese Frage gestoßen und habe die Tatsache, dass es keinen voll funktionsfähigen regulären Ausdruck gab, als persönliche Herausforderung empfunden.Ich glaube, ich habe es geschafft, einen regulären Ausdruck zu erstellen tut Funktioniert für alle Eingaben – vorausgesetzt, Sie können sie verwenden atomare Gruppierung/Possessivquantoren.

Natürlich bin ich mir nicht sicher, ob es das gibt Sind alle Varianten, die eine atomare Gruppierung, aber kein Lookaround ermöglichen, aber die Frage lautete, ob es in Regex möglich ist, einen Ausschluss ohne Lookaround anzugeben, und das auch Ist technisch möglich:

\A(?:$|[^f]++|f++(?:[^o]|$)|(?:f++o)*+(?:[^o]|$))*\Z

Erläuterung:

\A                         #Start of string
(?:                        #Non-capturing group
    $                      #Consume end-of-line. We're not in foo-mode.
    |[^f]++                #Consume every non-'f'. We're not in foo-mode.
    |f++(?:[^o]|$)          #Enter foo-mode with an 'f'. Consume all 'f's, but only exit foo-mode if 'o' is not the next character. Thus, 'f' is valid but 'fo' is invalid.
    |(?:f++o)*+(?:[^o]|$)  #Enter foo-mode with an 'f'. Consume all 'f's, followed by a single 'o'. Repeat, since '(f+o)*' by itself cannot contain 'foo'. Only exit foo-mode if 'o' is not the next character following (f+o). Thus, 'fo' is valid but 'foo' is invalid.
)*                         #Repeat the non-capturing group
\Z                         #End of string. Note that this regex only works in flavours that can match $\Z

Wenn Sie aus irgendeinem Grund die atomare Gruppierung verwenden können, aber keine Possessivquantoren oder Lookarounds, können Sie Folgendes verwenden:

\A(?:$|(?>[^f]+)|(?>f+)(?:[^o]|$)|(?>(?:(?>f+)o)*)(?:[^o]|$))*\Z

Wie andere jedoch betonen, ist es wahrscheinlich praktischer, eine Übereinstimmung einfach auf andere Weise zu negieren.

Sie können in der Regel für foo suchen und das Ergebnis der Regex vom Client-Code invertieren.

Für ein einfaches Beispiel, sagen wir, Sie überprüfen möchten, dass ein String nur bestimmte Zeichen enthält.

Sie können das so schreiben:

^[A-Za-z0-9.$-]*$

und akzeptieren ein true Ergebnis als gültig oder wie folgt aus:

[^A-Za-z0-9.$-]

und akzeptiert ein false Ergebnis als gültig.

Natürlich ist dies nicht immer eine Option: Manchmal müssen Sie nur noch den Ausdruck in einer Konfigurationsdatei setzen oder sie in ein anderes Programm übergeben, zum Beispiel. Aber es ist daran zu erinnern. Ihr spezifisches Problem, zum Beispiel der Ausdruck viel einfacher, wenn Sie Negation wie diese verwenden können.

ich auf dieser Frage gestolpert für meine eigene regex Ausschluss Lösung suchen, wo ich eine Sequenz ausschließen versuchen in meine regex.

Meine erste Reaktion auf diese Situation. Zum Beispiel „jede Zeile, die nicht hat‚foo‘on it“ wurde einfach den -v Invertzucker Sinn verwenden Option in grep passenden

grep -v foo

Dies gibt alle Zeilen in einer Datei, die nicht ‚foo‘ entspricht

Es ist so einfach ich das starke Gefühl haben habe ich nur Ihre Frage falsch verstanden ....

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top