Anticipation des regex, lookbehind et groupes atomiques

314

J'ai trouvé ces choses dans mon corps d'expression régulière, mais je n'ai aucune idée de la raison pour laquelle je peux les utiliser. Quelqu'un a-t-il des exemples pour que je puisse essayer de comprendre comment ils fonctionnent?

(?!) - negative lookahead
(?=) - positive lookahead
(?<=) - positive lookbehind
(?<!) - negative lookbehind

(?>) - atomic group
Spidfire
la source
18
Pourquoi le site regex n'a-t-il pas un tableau simple comme celui-ci? Au lieu de cela, ils ont des blocs de texte expliquant uniquement. regular-expressions.info/lookaround.html
Whitecat
3
@Whitecat Essayez: regex101.com regexr.com
Andrew

Réponses:

852

Exemples

Étant donné la chaîne foobarbarfoo:

bar(?=bar)     finds the 1st bar ("bar" which has "bar" after it)
bar(?!bar)     finds the 2nd bar ("bar" which does not have "bar" after it)
(?<=foo)bar    finds the 1st bar ("bar" which has "foo" before it)
(?<!foo)bar    finds the 2nd bar ("bar" which does not have "foo" before it)

Vous pouvez également les combiner:

(?<=foo)bar(?=bar)    finds the 1st bar ("bar" with "foo" before it and "bar" after it)

Définitions

Un regard positif sur l'avenir (?=)

Trouvez l'expression A où l'expression B suit:

A(?=B)

Regardez vers l'avenir négatif (?!)

Trouvez l'expression A où l'expression B ne suit pas:

A(?!B)

Regardez derrière positif (?<=)

Rechercher l'expression A où l'expression B précède:

(?<=B)A

Regardez derrière le négatif (?<!)

Rechercher l'expression A où l'expression B ne précède pas:

(?<!B)A

Groupes atomiques (?>)

Un groupe atomique quitte un groupe et jette des motifs alternatifs après le premier motif correspondant à l'intérieur du groupe (le retour arrière est désactivé).

  • (?>foo|foot)sappliqué footscorrespondra à sa 1ère alternative foo, puis échouera car sil ne suit pas immédiatement et s'arrêtera car le retour arrière est désactivé

Un groupe non atomique permettra le retour en arrière; si la correspondance suivante échoue, elle fera marche arrière et utilisera des modèles alternatifs jusqu'à ce qu'une correspondance pour l'expression entière soit trouvée ou que toutes les possibilités soient épuisées.

  • (foo|foot)sappliqué au footstestament:

    1. correspondre à sa 1ère alternative foo, puis échouer car sil ne suit pas immédiatement foots, et revenir à sa 2ème alternative;
    2. correspondre à sa 2e alternative foot, puis réussir comme ssuit immédiatement footset arrêter.

Quelques ressources

Testeurs en ligne

skyfoot
la source
1
Que voulez-vous dire par "trouve la deuxième barre"? Il n'y a qu'une seule barre dans l'expression / chaîne. Merci
ziggy
2
@ziggy la chaîne testée est "foobarbarfoo". Comme vous pouvez le voir, il y a deux foo et deux barres dans la chaîne.
skyfoot
4
Quelqu'un peut-il expliquer quand on peut avoir besoin d'un groupe atomique? Si je dois seulement correspondre à la première alternative, pourquoi voudrais-je proposer plusieurs alternatives?
arviman
2
Meilleure explication sur le groupe atomique à cette réponse . Quelqu'un peut-il modifier ici pour compléter cette réponse didactique?
Peter Krauss
5
Juste une note que cette réponse était essentielle lorsque je me suis retrouvé sur un projet qui nécessitait de sérieux côtelettes d'expression régulière. Il s'agit d'une excellente explication concise des contournements.
Tom Coughlin
215

Les contournements sont des assertions de largeur nulle. Ils recherchent une expression régulière (vers la droite ou la gauche de la position actuelle - en fonction de l'avant ou de l'arrière), réussissent ou échouent lorsqu'une correspondance est trouvée (selon qu'elle est positive ou négative) et rejette la partie correspondante. Ils ne consomment aucun caractère - la correspondance pour l'expression régulière qui les suit (le cas échéant), commencera à la même position du curseur.

Lisez regular-expression.info pour plus de détails.

  • Anticipation positive:

Syntaxe:

(?=REGEX_1)REGEX_2

Correspondance uniquement si REGEX_1 correspond; après avoir correspond à REGEX_1, la correspondance est annulée et la recherche de REGEX_2 commence à la même position.

exemple:

(?=[a-z0-9]{4}$)[a-z]{1,2}[0-9]{2,3}

REGEX_1 [a-z0-9]{4}$correspond à quatre caractères alphanumériques suivis de la fin de la ligne.
REGEX_2 [a-z]{1,2}[0-9]{2,3}correspond à une ou deux lettres suivies de deux ou trois chiffres.

REGEX_1 s'assure que la longueur de la chaîne est bien 4, mais ne consomme aucun caractère afin que la recherche de REGEX_2 commence au même emplacement. Maintenant, REGEX_2 s'assure que la chaîne correspond à d'autres règles. Sans anticipation, il correspondrait à des chaînes de longueur trois ou cinq.

  • Anticipation négative

Syntaxe:

(?!REGEX_1)REGEX_2

Correspondance uniquement si REGEX_1 ne correspond pas; après avoir vérifié REGEX_1, la recherche de REGEX_2 commence à la même position.

exemple:

(?!.*\bFWORD\b)\w{10,30}$

La partie d'anticipation vérifie la FWORDdans la chaîne et échoue si elle la trouve. S'il ne le trouve pas FWORD, l'anticipation réussit et la partie suivante vérifie que la longueur de la chaîne est comprise entre 10 et 30 et qu'elle ne contient que des caractères de mota-zA-Z0-9_

L'arrière-plan est similaire à l'anticipation: il regarde juste derrière la position actuelle du curseur. Certaines saveurs d'expression régulière comme javascript ne prennent pas en charge les assertions de recherche. Et la plupart des saveurs qui le prennent en charge (PHP, Python, etc.) nécessitent que cette partie en regard ait une longueur fixe.

  • Les groupes atomiques rejettent / oublient essentiellement les jetons suivants dans le groupe une fois qu'un jeton correspond. Consultez cette page pour des exemples de groupes atomiques
Amarghosh
la source
suite à votre explication, ne semble pas fonctionner en javascript, /(?=source)hello/.exec("source...hummhellosource ") = null. Votre explication est-elle correcte?
Helin Wang
@HelinWang Cette explication est correcte. Votre regex attend une chaîne qui est à la fois source et bonjour en même temps!
Amarghosh
@jddxf Vous voulez élaborer?
Amarghosh
@Amarghosh, je suis d'accord avec "Ils recherchent une expression régulière (vers la droite ou la gauche de la position actuelle - basée sur l'avant ou derrière), réussit ou échoue lorsqu'une correspondance est trouvée (selon qu'elle est positive ou négative) et rejette la correspondance portion.". Donc, l'anticipation devrait vérifier une expression régulière vers la droite de la position actuelle et la syntaxe de l'anticipation positive devrait être x (? = Y)
jddxf
@Amarghosh (?=REGEX_1)REGEX_2ne correspondrait que si REGEX_2vient après REGEX_1 ?
aandis
0

Grokking lookaround rapidement.
Comment distinguer l'anticipation et l'antériorité? Faites une visite de 2 minutes avec moi:

(?=) - positive lookahead
(?<=) - positive lookbehind

Supposer

    A  B  C #in a line

Maintenant, nous demandons à B, où êtes-vous?
B a deux solutions pour déclarer son emplacement:

Un, B a A devant et C est lié
Deux, B est devant (lookahead) de C et derrière (lookhehind) A.

Comme nous pouvons le voir, l'arrière et l'avant sont opposés dans les deux solutions.
Regex est la solution Deux.

Calcul
la source