quelle est la différence entre ?:, ?! et? = dans regex?

107

J'ai cherché la signification de ces expressions mais je n'ai pas pu comprendre la différence exacte entre elles. Voici ce qu'ils disent:

  • ?: Faites correspondre l'expression mais ne la capturez pas.
  • ?= Faites correspondre un suffixe mais excluez-le de la capture.
  • ?! Correspondance si le suffixe est absent.

J'ai essayé de les utiliser dans de simples RegEx et j'ai obtenu des résultats similaires pour tous. exemple: les 3 expressions suivantes donnent des résultats très similaires.

  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?!\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?=\.[a-zA-Z0-9]+)*
  • [a-zA-Z0-9._-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9]+)*
RK Poddar
la source
Veuillez nous montrer votre cas de test. Ils ne devraient pas donner les mêmes résultats.
Bergi
@ sepp2k, les mêmes résultats similaires dans peu de cas, l'un d'entre eux mentionné dans la question.
RK Poddar
@Bergi, je l'ai testé avec des données aléatoires, contenant des mots anglais, des numéros de téléphone, des URL, des adresses e-mail, des numéros, etc.
RK Poddar
4
@RKAgarwal Ah, je vois ce que vous avez fait là-bas. Vous avez ajouté un *après les groupes, ils sont donc simplement ignorés.
sepp2k
noobie note : vous ne les utiliseriez qu'au début de la parenthèse, et les parenthèses forment un groupe de capture (différents jeux de parenthèses extraient différentes sections de texte).
Ryan Taylor

Réponses:

152

La différence entre ?=et ?!est que le premier exige que l'expression donnée corresponde et le second ne doit pas correspondre. Par exemple a(?=b), correspondra le "a" dans "ab", mais pas le "a" dans "ac". Alors que a(?!b)correspondra le "a" dans "ac", mais pas le "a" dans "ab".

La différence entre ?:et ?=est que cela ?=exclut l'expression de toute la correspondance tout en ?:ne créant tout simplement pas de groupe de capture. Ainsi, par exemple a(?:b), correspondra le "ab" dans "abc", tandis que a(?=b)ne correspondra qu'au "a" dans "abc". a(b)correspondrait au "ab" de "abc" et créerait une capture contenant le "b".

sepp2k
la source
80
?:  is for non capturing group
?=  is for positive look ahead
?!  is for negative look ahead
?<= is for positive look behind
?<! is for negative look behind

Veuillez vérifier ici: http://www.regular-expressions.info/lookaround.html pour un très bon tutoriel et des exemples sur lookahead dans les expressions régulières.

anubhava
la source
15
Pourtant, JavaScript ne sait pas regarder en arrière.
Bergi
1
Celui-ci est plus complet pour les regex générales.
Yan Yang
/ (? <= ^ a) b / a fonctionné pour moi en javascript! Il ne semble pas y avoir de tutoriel pour regarder en arrière en Javascript sur Internet.
Y. Yoshii
Seules les versions récentes des navigateurs ont commencé à prendre en charge look behind dans JS
anubhava
- anubhava Je ne connais pas d'alternative à / (? <= ^ A) b / en utilisant l'expression régulière pure. Peut-être que je peux mais je devrais me fier aux fonctions de rappel.
Y. Yoshii
21

Pour mieux comprendre, appliquons les trois expressions plus un groupe de capture et analysons chaque comportement.

  • () groupe de capture - l'expression régulière à l'intérieur des parenthèses doit être mise en correspondance et la correspondance crée un groupe de capture
  • (?:) groupe non capturant - l'expression régulière à l'intérieur de la parenthèse doit correspondre mais ne crée pas le groupe de capture
  • (?=) positive look ahead - affirme que l'expression régulière doit être mise en correspondance
  • (?!) look négatif - affirme qu'il est impossible de faire correspondre l'expression régulière

Appliquons q(u)ipour arrêter . qcorrespond à q et le groupe de capture ucorrespond à u . La correspondance à l'intérieur du groupe de capture est prise et un groupe de capture est créé. Le moteur continue donc i. Et icorrespondra à i . Cette dernière tentative de match est réussie. qui est mis en correspondance et un groupe de capture avec u est créé.

Appliquons q(?:u)ipour arrêter . Encore une fois, qcorrespond à q et le groupe non capturant ucorrespond à u . La correspondance du groupe de non-capture est prise, mais le groupe de capture n'est pas créé. Le moteur continue donc i. Et icorrespondra à i . Cette dernière tentative de match est réussie. qui correspond

Appliquons q(?=u)ipour arrêter . La recherche anticipée est positive et est suivie d'un autre jeton. Encore une fois, qcorrespond à q et ucorrespond à u . Encore une fois, la correspondance de l'anticipation doit être rejetée, de sorte que le moteur revient de ila chaîne à u . Le lookahead a réussi, donc le moteur continue i. Mais ipeut ne pas correspondre u . Donc, cette tentative de match échoue.

Appliquons q(?=u)upour arrêter . La recherche anticipée est positive et est suivie d'un autre jeton. Encore une fois, qcorrespond à q et ucorrespond à u . La correspondance de l'anticipation doit être ignorée, de sorte que le moteur revient de ula chaîne à u . Le lookahead a réussi, donc le moteur continue u. Et ucorrespondra u . Donc cette tentative de match est réussie. qu est apparié

Appliquons q(?!i)upour arrêter . Même dans ce cas, la recherche anticipée est positive (car ine correspond pas) et est suivie d'un autre jeton. Encore une fois, qcorrespond à q et ine correspond pas à u . La correspondance de l'anticipation doit être ignorée, de sorte que le moteur revient de ula chaîne à u . Le lookahead a réussi, donc le moteur continue u. Et ucorrespondra u . Donc cette tentative de match est réussie. qu est apparié

Donc, en conclusion, la vraie différence entre les groupes lookahead et non-captur est de savoir si vous voulez simplement tester l'existence ou tester et enregistrer la correspondance. Les groupes de capture sont chers alors utilisez-les judicieusement.

Freedev
la source
> ainsi le moteur recule de i dans la chaîne à u. Le lookahead a réussi, donc le moteur continue avec i. Mais je ne peux pas vous correspondre CECI est totalement déroutant. Pourquoi prendre du recul si c'est anticipé ?
vert
1
@Green Une chose importante à comprendre à propos de la recherche anticipée et des autres constructions de recherche est que bien qu'ils parcourent les mouvements pour voir si leur sous-expression est capable de correspondre, ils ne «consomment» en fait aucun texte. Cela peut être un peu déroutant
Freedev
7

Essayez de comparer foobaravec ceux-ci:

/foo(?=b)(.*)/
/foo(?!b)(.*)/

La première expression régulière correspondra et renverra «bar» comme premier sous- (?=b)match - correspond au «b», mais ne le consomme pas, le laissant pour les parenthèses suivantes.

La deuxième regex ne correspondra PAS, car elle s'attend à ce que «foo» soit suivi par quelque chose de différent de «b».

(?:...)a exactement le même effet que simple (...), mais il ne renvoie pas cette partie en tant que sous-correspondance.

Lanzz
la source
0

Le moyen le plus simple de comprendre les assertions est de les traiter comme la commande insérée dans une expression régulière. Lorsque le moteur exécute une assertion, il vérifie immédiatement la condition décrite par l'assertion. Si le résultat est vrai, continuez à exécuter l'expression régulière.

BlackGlory
la source
0

C'est la vraie différence:

>>> re.match('a(?=b)bc', 'abc')
<Match...>
>>> re.match('a(?:b)c', 'abc')
<Match...>

# note:
>>> re.match('a(?=b)c', 'abc')
None

Si vous ne vous souciez pas du contenu après "?:" Ou "? =", "?:" Et "? =" Sont exactement les mêmes. Les deux peuvent être utilisés.

Mais si vous avez besoin de ce contenu pour un traitement ultérieur (pas seulement pour correspondre au tout. Dans ce cas, vous pouvez simplement utiliser "a (b)") Vous devez utiliser "? =" À la place. Cause "?:" Sera juste à travers cela loin.

Buveur de thé
la source