É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.
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.
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
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)
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.
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 a
ET la lettre b
.
Cela fonctionne aussi avec des groupes:
var re = /(co)(de)/;
cela signifie que le groupe co
ET le groupe de
.
Remplacer le (implicite) AND par un OR nécessiterait les lignes suivantes:
var re = /a|b/;
var re = /(co)|(de)/;
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) && ...
Pourquoi ne pas utiliser awk?
Avec awk regex ET, OR La matière est si simple
awk '/Word1/ && /Word2/ && /Word3/' myfile
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
Vous pouvez diriger votre sortie vers un autre regex. En utilisant grep, vous pouvez faire ceci:
grep A | grep B
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
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.
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.