Expressions régulières: y a-t-il un opérateur et?

évidemment, vous pouvez utiliser le | (pipe?) pour représenter OR , mais y a-t-il aussi une façon de représenter AND ?

plus précisément, j'aimerais faire correspondre les paragraphes du texte qui contiennent tous une certaine phrase, mais dans aucun ordre particulier.

543
demandé sur vijrox 2009-01-22 19:49:14

12 réponses

utilisez une expression régulière non consommatrice.

la notation typique (Perl / Java) est:

(?= expr )

cela signifie "match expr mais après cela continuer à correspondre au point de match original."

Vous pouvez 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 des expressions non consommatrices si vous avez besoin de sauvegarder certaines des données qu'elles contiennent.

316
répondu Jason Cohen 2009-01-22 20:57:12

vous devez utiliser lookahead comme certains des autres répondants l'ont dit, mais le lookahead doit tenir compte d'autres caractères entre son mot cible et la position de correspondance actuelle. Par exemple:

(?=.*word1)(?=.*word2)(?=.*word3)

le .* dans le premier lookahead lui permet de correspondre à tous les caractères dont il a besoin avant qu'il arrive à"word1". Puis la position de correspondance est réinitialisée et la seconde lookahead recherche "word2". Réinitialiser à nouveau, et la partie finale correspond à " word3"; puisque c'est le dernier mot que vous cherchez, il n'est pas nécessaire que ce soit dans un lookahead, mais ça ne fait pas mal.

pour correspondre à un paragraphe entier, vous devez ancrer la regex aux deux extrémités et Ajouter un final .* pour consommer les caractères restants. En utilisant la notation Perl-style, ce serait:

/^(?=.*word1)(?=.*word2)(?=.*word3).*$/m

le modificateur 'm' est pour le mode multline; il permet de faire correspondre ^ et $ aux limites du paragraphe ("ligne les frontières" en regex parler). Il est essentiel dans ce cas que vous et non utilisez le modificateur 's', qui permet au point metacharacter de correspondre aux nouvelles lignes ainsi que 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, donc vous devez ajouter des limites de mots:

/^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$/m
272
répondu Alan Moore 2009-01-22 20:04:11

regardez cet exemple:

nous avons 2 regexps A et B et nous voulons faire correspondre les deux, donc en pseudo-code il ressemble à ceci:

pattern = "/A AND B/"

il peut être écrit sans utiliser L'opérateur et comme ceci:

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

in PCRE:

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

regexp_match(pattern,data)
30
répondu fanjabi 2011-11-14 19:11:11

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

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

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

cependant, cela rend un regexp très long et probablement inefficace, si vous avez plus de termes de couple.

Si vous utilisez certains version regexp étendue, comme Perl ou Java, ils ont de meilleures façons de le faire. D'autres réponses ont suggéré d'utiliser l'opération positive lookahead.

22
répondu Juha Syrjälä 2009-01-22 18:41:20

l'opérateur et est implicite dans la syntaxe RegExp.

L'opérateur OU, au contraire, être spécifié avec un tuyau.

Le RegExp suivant:

var re = /ab/;

signifie la lettre a et la lettre b .

Il travaille également avec des groupes:

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

signifie le groupe co et le groupe de .

Remplacer le (implicite) et par un bloc opératoire nécessiterait les lignes suivantes:

var re = /a|b/;
var re = /(co)|(de)/;
12
répondu Emanuele Del Grande 2017-08-22 12:31:06

pourquoi ne pas utiliser awk?

avec awk regex et, ou les choses est si simple

awk '/WORD1/ && /WORD2/ && /WORD3/' myfile
9
répondu mug896 2013-12-27 16:31:09

il n'Est pas possible dans votre cas à faire ET sur plusieurs résultats correspondant? en pseudo-code

regexp_match(pattern1, data) && regexp_match(pattern2, data) && ...
8
répondu user54579 2009-01-22 16:57:52

si vous utilisez des expressions régulières Perl, vous pouvez utiliser lookahead positif:

par exemple

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

serait des nombres supérieurs à 100 et divisible par 5

8
répondu jpalecek 2009-01-22 16:59:30

vous pourriez pipe votre production à un autre regex. En utilisant grep, vous pouvez faire ceci:

grep A | grep B

6
répondu garbagecollector 2014-11-20 21:36:21

en plus de la réponse acceptée

je vais vous fournir quelques exemples pratiques qui éclaireront 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 est de choisir le signe+, mais seulement si c'est après deux les numéros avec l'espace et si c'est avant quatre numéros. Ceux 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, elle vous donnera des résultats différents.

ou peut-être voulez-vous sélectionner un texte entre les balises... mais pas les balises! Vous pouvez alors utiliser:

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

pour ce texte:

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

voir Démo ici DÉMO

2
répondu DevWL 2018-02-01 02:06:55

L'ordre est toujours implicite dans la structure de l'expression régulière. Pour accomplir ce que vous voulez, vous devrez apparier la chaîne de caractères plusieurs fois avec différentes expressions.

Ce que vous voulez faire est de pas possible avec un seul regexp.

0
répondu pilif 2009-01-22 16:56:05

utiliser et en dehors de l'expression régulière. En PHP lookahead opérateur ne semble pas fonctionner pour moi, à la place, j'ai utilisé ce

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

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

0
répondu Hammad Khan 2011-09-09 18:13:04