Comment faire correspondre «n'importe quoi jusqu'à cette séquence de caractères» dans une expression régulière?

515

Prenez cette expression régulière: /^[^abc]/. Cela correspondra à n'importe quel caractère au début d'une chaîne, à l'exception de a, b ou c.

Si vous ajoutez un *après - /^[^abc]*/- l'expression régulière continuera à ajouter chaque caractère suivant le résultat, jusqu'à ce qu'il rencontre soit un a, ou b , ou c .

Par exemple, avec la chaîne source "qwerty qwerty whatever abc hello", l'expression correspondra à "qwerty qwerty wh".

Mais si je voulais que la chaîne correspondante soit "qwerty qwerty whatever "

... En d'autres termes, comment puis-je faire correspondre tout (sans inclure) la séquence exacte "abc" ?

callum
la source
Qu'entendez-vous par match but not including?
Toto
5
Je veux dire que je veux faire correspondre "qwerty qwerty whatever "- sans inclure le "abc". En d'autres termes, je ne veux pas que la correspondance résultante soit "qwerty qwerty whatever abc".
callum
2
En javascript, vous pouvez simplement do string.split('abc')[0]. Certainement pas une réponse officielle à ce problème, mais je le trouve plus simple que regex.
Wylliam Judd

Réponses:

1023

Vous n'avez pas spécifié quelle saveur de regex vous utilisez, mais cela fonctionnera dans l'un des plus populaires qui peuvent être considérés comme "complets".

/.+?(?=abc)/

Comment ça fonctionne

La .+? partie est la version non gourmande de .+ (un ou plusieurs de n'importe quoi). Lorsque nous utilisons .+, le moteur correspondra à tout. Ensuite, s'il y a autre chose dans l'expression régulière, elle reviendra par étapes en essayant de faire correspondre la partie suivante. C'est le comportement gourmand , c'est- à- dire autant que possible à satisfaire .

Lors de l'utilisation .+?, au lieu de faire correspondre tout à la fois et de revenir à d'autres conditions (le cas échéant), le moteur fera correspondre les caractères suivants par étape jusqu'à ce que la partie suivante de l'expression régulière soit mise en correspondance (à nouveau le cas échéant). C'est le non gourmand , c'est -à- dire le match le moins possible à satisfaire .

/.+X/  ~ "abcXabcXabcX"        /.+/  ~ "abcXabcXabcX"
          ^^^^^^^^^^^^                  ^^^^^^^^^^^^

/.+?X/ ~ "abcXabcXabcX"        /.+?/ ~ "abcXabcXabcX"
          ^^^^                          ^

Après cela, nous avons , une assertion de largeur nulle , un regard autour . Cette construction groupée correspond à son contenu, mais ne compte pas comme des caractères correspondants ( largeur nulle ). Il ne retourne que s'il s'agit d'une correspondance ou non ( assertion ).(?={contents})

Ainsi, en d'autres termes, l'expression régulière /.+?(?=abc)/signifie:

Faites correspondre le moins de caractères possible jusqu'à ce qu'un "abc" soit trouvé, sans compter le "abc".

Sidylle
la source
12
Cela ne fonctionnera probablement pas avec les sauts de ligne, s'ils sont censés être capturés.
einord
3
Quelle est la différence entre .+?et .*?
robbie
4
@ robbie0630 +signifie 1 ou plus, où *0 ou plus. L'inclusion / exclusion de la ?rendra gourmande ou non gourmande.
jinglesthula
2
@ testerjoe2 /.+?(?=abc|xyz)/
JohnWrensby
4
J'ai remarqué que cela ne sélectionne rien si le motif que vous recherchez n'existe pas, mais si vous utilisez, ^(?:(?!abc)(?!def).)*vous pouvez chaîner pour exclure les motifs que vous ne voulez pas et il récupérera tout comme nécessaire, même si le motif n'existe pas
Karan Shishoo
123

Si vous cherchez à tout capturer jusqu'à "abc":

/^(.*?)abc/

Explication:

( )capturer l'expression à l' intérieur des parenthèses pour l' accès à l' aide $1, $2etc.

^ correspondre au début de la ligne

.*correspondre à n'importe quoi, ?sans gourmandise (correspondre au nombre minimum de caractères requis) - [1]

[1] La raison pour laquelle cela est nécessaire est que sinon, dans la chaîne suivante:

whatever whatever something abc something abc

par défaut, les regex sont gourmandes , ce qui signifie qu'elles correspondront autant que possible. Par conséquent /^.*abc/, correspondrait à "quoi que ce soit quelque chose abc quelque chose". L'ajout du quantificateur non gourmand ?fait que l'expression régulière ne correspond qu'à «quoi que ce soit».

Jared Ng
la source
4
Merci, mais celui- ci inclut l'abc dans le match. En d'autres termes, la correspondance résultante est "quoi que ce soit quelque chose d'abc".
callum
1
Pourriez-vous expliquer ce que vous essayez finalement de faire? Si votre scénario est: (A) Vous voulez obtenir tout ce qui mène à "abc" - utilisez simplement des parenthèses autour de ce que vous voulez capturer. (B) Vous voulez faire correspondre la chaîne à "abc" - vous devez quand même vérifier l'abc, donc elle doit faire partie du regex malgré tout. Sinon, comment pouvez-vous vérifier qu'il est là?
Jared Ng
sedne semble pas prendre en charge la correspondance non gourmande, ni la recherche autour ( (?=...)). Que puis-je faire d'autre? Exemple de commande: echo "ONE: two,three, FOUR FIVE, six,seven" | sed -n -r "s/^ONE: (.+?), .*/\1/p"retourne two,three, FOUR FIVE, mais j'attends two,three...
CodeManX
1
@CoDEmanX Vous devriez probablement poster cela comme votre propre question plutôt que comme un commentaire, d'autant plus qu'il s'agit spécifiquement de sed. Cela étant dit, pour répondre à votre question: vous voudrez peut-être examiner les réponses à cette question . Notez également que dans votre exemple, un interpréteur non gourmand ne retournera twopas, pas two,three.
Jared Ng
3
Voici à quoi devrait ressembler CHAQUE réponse d'expression
régulière
54

Comme l'ont souligné @Jared Ng et @Issun, la clé pour résoudre ce type de RegEx comme "tout faire correspondre jusqu'à un certain mot ou une sous-chaîne" ou "tout faire correspondre après un certain mot ou une certaine sous-chaîne" est appelée assertions de longueur nulle "lookaround" . En savoir plus à leur sujet ici.

Dans votre cas particulier, cela peut être résolu par un regard positif sur l'avenir: .+?(?=abc)

Une image vaut mieux que mille mots. Voir l'explication détaillée dans la capture d'écran.

Regex101 Screenshot

Devy
la source
23
.+?(?=abc)regex copier-coller vaut plus.
Tom
Qu'en est-il de l'exclusion des espaces principaux?
Royi
8

Ce dont vous avez besoin, c'est de regarder autour de l'assertion comme .+? (?=abc).

Voir: Lookahead et Lookbehind Zero-Length Assertions

Sachez que ce [abc]n'est pas la même chose que abc. Entre crochets, ce n'est pas une chaîne - chaque caractère n'est qu'une des possibilités. En dehors des crochets, il devient la chaîne.

aevanko
la source
7

Pour regex en Java, et je crois aussi dans la plupart des moteurs regex, si vous voulez inclure la dernière partie, cela fonctionnera:

.+?(abc)

Par exemple, dans cette ligne:

I have this very nice senabctence

sélectionner tous les caractères jusqu'à "abc" et inclure également abc

en utilisant notre regex, le résultat sera: I have this very nice senabc

Testez cela: https://regex101.com/r/mX51ru/1

Dadan
la source
4

Je me suis retrouvé dans cette question de stackoverflow après avoir cherché de l'aide pour résoudre mon problème, mais je n'ai trouvé aucune solution :(

J'ai donc dû improviser ... après un certain temps, j'ai réussi à atteindre l'expression régulière dont j'avais besoin:

entrez la description de l'image ici

Comme vous pouvez le voir, j'avais besoin d'un dossier avant le dossier "grp-bps", sans inclure le dernier tiret. Et il fallait avoir au moins un dossier après le dossier "grp-bps".

Éditer

Version texte pour copier-coller (changez 'grp-bps' pour votre texte):

.*\/grp-bps\/[^\/]+
Loaderon
la source
6
Pas de version texte? 🙄
kiradotee
2

Cela aura un sens sur l'expression régulière.

  1. Le mot exact peut être obtenu à partir de la commande regex suivante:

("(.*?)")/g

Ici, nous pouvons obtenir le mot exact globalement qui appartient à l'intérieur des guillemets doubles. Par exemple, si notre texte de recherche est,

Voici l'exemple des mots "entre guillemets"

nous obtiendrons alors "double guillemet" de cette phrase.

Ponmurugan Mohanraj
la source
Bienvenue sur StackOverflow et merci pour votre tentative d'aide. Je trouve cependant difficile de voir en quoi cela contribue à l'objectif énoncé dans la question. Peux-tu élaborer? Pouvez-vous l'appliquer aux exemples donnés? Vous semblez vous concentrer sur la gestion de "ce qui, à mes yeux, ne semble pas pertinent pour la question.
Yunnosch
1
Bonjour, j'ai expliqué comment placer le mot ou les phrases entre les caractères spéciaux. Ici, notre question est aussi "n'importe quoi jusqu'à la séquence de caractères spéciaux". J'ai donc essayé avec des guillemets doubles et je l'ai expliqué ici. Merci.
Ponmurugan Mohanraj
2

Sur python:

.+?(?=abc) fonctionne pour le cas d'une seule ligne.

[^]+?(?=abc)ne fonctionne pas, car python ne reconnaît pas [^] comme expression régulière valide. Pour que la correspondance multiligne fonctionne, vous devrez utiliser l'option re.DOTALL, par exemple:

re.findall('.+?(?=abc)', data, re.DOTALL)
David Mulder
la source
0

Je pense que vous avez besoin de sous-expressions. Si je me souviens bien, vous pouvez utiliser les ()crochets normaux pour les sous-expressions.

Cette partie est du manuel de grep:

 Back References and Subexpressions
       The back-reference \n, where n is a single digit, matches the substring
       previously matched  by  the  nth  parenthesized  subexpression  of  the
       regular expression.

Faire quelque chose comme ^[^(abc)]ça devrait faire l'affaire.

Nandhini Anand
la source
Désolé, ça ne marche pas. Mettre l'abc entre parenthèses ne semble pas faire de différence. Ils sont toujours traités comme "a OR b OR c".
callum
-1

Le $marque la fin d'une chaîne, donc quelque chose comme ça devrait fonctionner: [[^abc]*]$où vous cherchez quelque chose qui ne se termine PAS dans une itération de abc, mais cela devrait être à la fin

De plus, si vous utilisez un langage de script avec regex (comme php ou js), ils ont une fonction de recherche qui s'arrête quand il rencontre pour la première fois un modèle (et vous pouvez spécifier commencer par la gauche ou commencer par la droite, ou avec php, vous pouvez faire un implosage pour refléter la chaîne).

Jacob
la source
-6

essaye ça

.+?efg

Requete :

select REGEXP_REPLACE ('abcdefghijklmn','.+?efg', '') FROM dual;

production :

hijklmn
Balakrishna Gondesi
la source