Question

Dans certains types d’expression regex, les assertions [négatives] de largeur nulle (recherche future / anticipée) ne sont pas prises en charge.

Cela rend extrêmement difficile (impossible?) d’énoncer une exclusion. Par exemple, "chaque ligne dont ne dispose pas " n'a pas "foo". dessus ", comme ceci:

^((?!foo).)*$

Peut-on obtenir le même résultat sans recourir à une simple recherche (problèmes de complexité et de performances laissés de côté pour le moment)?

Était-ce utile?

La solution

UPDATE: Il échoue "avec deux ff avant oo". comme @Ciantic a souligné dans les commentaires .

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

REMARQUE: il est beaucoup plus facile de nier une correspondance côté client au lieu d'utiliser la regex ci-dessus.

Les expressions rationnelles supposent que chaque ligne se termine par un caractère de nouvelle ligne si ce n'est pas le cas, consultez les expressions rationnelles de C ++ et de grep.

Les exemples de programmes en Perl, Python, C ++ et grep donnent tous le même résultat.

  • 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])*
    #include <iostream>
    #include <string>
    #include <boost/regex.hpp>
    
    int main()
    {
      boost::regex re("^(f(o([^o]|$)|([^o]|$))|[^f])*
    $ grep "^\(f\(o\([^o]\|$\)\|\([^o]\|$\)\)\|[^f]\)*
    foo
    'foo'
    abdfoode
    abdfode
    abdfde
    abcde
    f
    
    fo
    foo
    fooo
    ofooa
    ofo
    ofoo
    
    quot; in.txt
    quot;); //NOTE: "|
    abdfode
    abdfde
    abcde
    f
    
    fo
    ofo
    
    quot;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; }
    quot;) for line in ifilter(re_not_foo.match, fileinput.input()): sys.stdout.write(line)
  • c ++

    <*>
  • grep

    <*>

Exemple de fichier:

<*>

Sortie:

<*>

Autres conseils

Je suis tombé sur cette question et avons pris le fait qu’il n’y avait pas de regex pleinement fonctionnel comme un défi personnel. Je pense avoir réussi à créer une expression rationnelle qui fonctionne pour toutes les entrées - à condition que vous puissiez utiliser groupement atomique / quantificateurs possessifs .

Bien sûr, je ne suis pas sûr s'il existe des variantes qui permettent le groupement atomique mais non la recherche, mais la question demandait s'il était possible dans une regex d'énoncer une exclusion sans recherche, et elle < em> est techniquement possible:

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

Explication:

\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

Si, pour une raison quelconque, vous pouvez utiliser le groupement atomique mais pas les quantificateurs possessifs ni les comparaisons, vous pouvez utiliser:

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

Comme d'autres l'ont déjà fait remarquer, il est probablement plus pratique de simplement nier une correspondance par d'autres moyens.

Vous pouvez généralement rechercher foo et inverser le résultat de la correspondance d'expression régulière à partir du code client.

Pour un exemple simple, supposons que vous vouliez vérifier qu'une chaîne de caractères ne contient que certains caractères.

Vous pouvez écrire cela comme ceci:

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

et acceptez un résultat true comme valide ou comme ceci:

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

et acceptez le résultat false comme valide.

Bien sûr, ce n’est pas toujours une option: il vous suffit parfois de placer l’expression dans un fichier de configuration ou de la transmettre à un autre programme, par exemple. Mais ça vaut la peine de s'en souvenir. Votre problème spécifique, par exemple, l’expression est beaucoup beaucoup plus simple si vous pouvez utiliser la négation de la sorte.

Je suis tombé sur cette question à la recherche de ma propre solution d’exclusion de regex, dans laquelle j’essaie d’exclure une séquence au sein de mon regex.

Ma première réaction à cette situation: Par exemple, "toutes les lignes sans" foo ". sur celui-ci "" consistait simplement à utiliser l'option de correspondance de sens -v inverse dans grep.

grep -v foo

ceci renvoie toutes les lignes d'un fichier qui ne correspondent pas à "foo"

C’est tellement simple que j’ai le sentiment que je viens de mal interpréter votre question ....

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top