web-dev-qa-db-fra.com

Expressions régulières: Y a-t-il un opérateur AND?

Évidemment, vous pouvez utiliser le | (pipe?) Pour représenter OR, mais existe-t-il un moyen de représenter AND également?

Plus précisément, j'aimerais faire correspondre les paragraphes de texte qui contiennent TOUTES une certaine phrase, mais sans ordre particulier.

630
Hugoware

Utilisez une expression régulière non consommatrice.

La notation typique (c'est-à-dire Perl/Java) est la suivante:

(?=expr)

Cela signifie "match expr mais après cela continue à correspondre au point de match d'origine."

Vous pouvez en faire autant que vous voulez, et ce sera un "et". Exemple:

(?=match this expression)(?=match this too)(?=oh, and this)

Vous pouvez même ajouter des groupes de capture à l'intérieur d'expressions non consommatrices si vous avez besoin de sauvegarder certaines données.

352
Jason Cohen

Vous devez utiliser lookahead comme l'ont dit certains des autres répondants, mais le lookahead doit prendre en compte les autres caractères situés entre le mot cible et la position du match en cours. Par exemple:

(?=.*Word1)(?=.*Word2)(?=.*Word3)

Le .* dans le premier aperçu permet de faire correspondre le nombre de caractères requis avant d'arriver à "Word1". Ensuite, la position du match est réinitialisée et le deuxième espion recherche "Word2". Réinitialisez à nouveau et la dernière partie correspond à "Word3"; comme c'est le dernier mot que vous recherchez, il n'est pas nécessaire qu'il soit dans un état prévisionnel, mais cela ne fait pas mal.

Afin de faire correspondre un paragraphe entier, vous devez ancrer l'expression régulière aux deux extrémités et ajouter un dernier .* pour utiliser les caractères restants. En utilisant une notation de style Perl, ce serait:

/^(?=.*Word1)(?=.*Word2)(?=.*Word3).*$/m

Le modificateur 'm' est pour le mode multicanal; il laisse le ^ et le $ correspondre aux limites de paragraphe ("limites de ligne" en langage regex). Il est essentiel dans ce cas que vous n'utilisiez pas le modificateur 's', qui permet au métacaractère de points de correspondre aux nouvelles lignes ainsi qu'à tous les autres caractères.

Enfin, vous voulez vous assurer que vous faites correspondre des mots entiers et pas seulement des fragments de mots plus longs, vous devez donc ajouter des limites de Word:

/^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$/m
313
Alan Moore

Regardez cet exemple:

Nous avons 2 expressions rationnelles A et B et nous voulons les faire correspondre. En pseudo-code, cela ressemble à ceci:

pattern = "/A AND B/"

Cela peut être écrit sans utiliser l'opérateur AND comme ceci:

pattern = "/NOT (NOT A OR NOT B)/"

en PCRE:

"/^(^A|^B)/"

regexp_match(pattern,data)
29
fanjabi

Vous pouvez le faire avec une expression régulière, mais vous voudrez probablement en utiliser une autre. Par exemple, utilisez plusieurs expressions rationnelles et combinez-les dans une clause if.

Vous pouvez énumérer toutes les permutations possibles avec une expression rationnelle standard, comme ceci (correspond à a, b et c dans n'importe quel ordre):

(abc)|(bca)|(acb)|(bac)|(cab)|(cba)

Cependant, cela fait une expression rationnelle très longue et probablement inefficace, si vous avez plus que deux termes.

Si vous utilisez une version regexp étendue, telle que celle de Perl ou de Java, ils ont de meilleures façons de le faire. D'autres réponses ont suggéré d'utiliser une opération d'anticipation positive.

27
Juha Syrjälä

L'opérateur AND est implicite dans la syntaxe RegExp.
L'opérateur OR doit plutôt être spécifié avec un tuyau.
Le RegExp suivant:

var re = /ab/;

signifie la lettre aET la lettre b.
Cela fonctionne aussi avec des groupes:

var re = /(co)(de)/;

cela signifie que le groupe coET le groupe de.
Remplacer le (implicite) AND par un OR nécessiterait les lignes suivantes:

var re = /a|b/;
var re = /(co)|(de)/;
20

N’est-il pas possible dans votre cas de faire l’ET sur plusieurs résultats correspondants? en pseudocode

regexp_match(pattern1, data) && regexp_match(pattern2, data) && ...
10
user54579

Pourquoi ne pas utiliser awk?
Avec awk regex ET, OR La matière est si simple

awk '/Word1/ && /Word2/ && /Word3/' myfile
9
mug896

Si vous utilisez des expressions régulières Perl, vous pouvez utiliser un préfixe positif:

Par exemple

(?=[1-9][0-9]{2})[0-9]*[05]\b

serait un nombre supérieur à 100 et divisible par 5

8
jpalecek

Vous pouvez diriger votre sortie vers un autre regex. En utilisant grep, vous pouvez faire ceci:

grep A | grep B

7
garbagecollector

En plus de la réponse acceptée

Je vais vous donner quelques exemples pratiques qui clarifieront les choses pour certains d'entre vous. Par exemple, disons que nous avons ces trois lignes de texte:

[12/Oct/2015:00:37:29 +0200] // only this + will get selected
[12/Oct/2015:00:37:x9 +0200]
[12/Oct/2015:00:37:29 +020x]

Voir la démo ici DÉMO

Ce que nous voulons faire ici, c'est sélectionner le signe +, mais seulement si c'est après deux nombres avec un espace et s'il est avant quatre chiffres. Ce sont les seules contraintes. Nous utiliserions cette expression régulière pour y parvenir:

'~(?<=\d{2} )\+(?=\d{4})~g'

Notez que si vous séparez l'expression, vous obtiendrez des résultats différents.

Ou peut-être souhaitez-vous sélectionner du texte entre les balises ... mais pas les balises! Ensuite, vous pouvez utiliser:

'~(?<=<p>).*?(?=<\/p>)~g'

pour ce texte:

<p>Hello !</p> <p>I wont select tags! Only text with in</p> 

Voir la démo ici DÉMO

5
DevWL

L'ordre est toujours impliqué dans la structure de l'expression régulière. Pour accomplir ce que vous voulez, vous devrez faire correspondre la chaîne d'entrée plusieurs fois avec différentes expressions.

Ce que vous voulez faire est pas possible avec une seule expression rationnelle.

3
pilif

Utilisez ET en dehors de l'expression régulière. Dans PHP, l'opérateur de lookahead ne semblait pas fonctionner pour moi, mais j'ai utilisé

if( preg_match("/^.{3,}$/",$pass1) && !preg_match("/\s{1}/",$pass1))
    return true;
else
    return false;

La regex ci-dessus correspondra si la longueur du mot de passe est de 3 caractères ou plus et qu'il n'y a pas d'espace dans le mot de passe.

0
Hammad Khan