Regex: correspondance jusqu'à la première occurrence d'un personnage

358

Je cherche un motif qui correspond à tout jusqu'à la première occurrence d'un caractère spécifique, disons un ";" - un point - virgule .

J'ai écrit ceci:

/^(.*);/

Mais il correspond en fait à tout (y compris le point-virgule) jusqu'à la dernière occurrence d'un point-virgule.

Leon Fedotov
la source
65
/^(.*?);/devrait également fonctionner (cela s'appelle non gourmand ), mais les réponses données en utilisant [^;]*sont meilleures.
Pascal
comment choisiriez-vous tout, après le point-virgule, et non le point-virgule lui-même.
Muhammad Umer
voir cela fonctionne, \w+(?!([^]+;)|;)mais cela ne veut pas pourquoi? .+(?!([^]+;)|;)
Muhammad Umer
1
Pascal, tu aurais dû écrire ça comme réponse!
Sean Kendle
@Pascal Cela convient comme réponse! Merci!
neverMind9

Réponses:

503

Vous avez besoin

/[^;]*/

Le [^;]est une classe de caractères , elle correspond à tout sauf un point-virgule.

Pour citer la perlrepage de manuel:

Vous pouvez spécifier une classe de caractères, en joignant une liste de caractères entre [], qui correspondra à n'importe quel caractère de la liste. Si le premier caractère après le "[" est "^", la classe correspond à tout caractère ne figurant pas dans la liste.

Cela devrait fonctionner dans la plupart des dialectes regex.

sleske
la source
La grande partie de cette solution est qu'elle correspond également à la fin de la ligne, par exemple dans mon cas, j'avais foo=bar;baz=bax;bab=bafet elle correspondait bab=bafmême s'il n'y a pas ;exactement ce dont j'ai besoin. Je ne sais pas pourquoi cela fonctionne bien si la spécification dit que tout correspond sauf le symbole cible ...
skryvets
303

Aurait;

/^(.*?);/

travail?

L' ?opérateur est paresseux, donc l'expression régulière prend le moins possible avant de faire correspondre le ;.

RJFalconer
la source
4
Oui, mais suite à l'extension de bicarbonate à Tim Toady, je crois que les classes de personnages niés gagnent car le quantificateur paresseux inclut le backtraking. +1 de toute façon.
Amarghosh
3
À lire sur le sujet de la performance: blog.stevenlevithan.com/archives/greedy-lazy-performance
Glenn Slaven
38

/^[^;]*/

Le [^;] dit correspondre à tout sauf un point-virgule. Les crochets sont un opérateur de correspondance d'ensemble, il s'agit essentiellement de faire correspondre n'importe quel caractère de cet ensemble de caractères, ^au début, il s'agit d'une correspondance inverse, donc faites correspondre tout ce qui ne se trouve pas dans cet ensemble.

Glenn Slaven
la source
3
Sachez que le premier ^ de cette réponse donne au regex une signification complètement différente: il fait que l'expression régulière ne recherche que les correspondances commençant au début de la chaîne. Dans ce cas, ce serait effectivement un no-op si vous n'exécutez l'expression régulière qu'une seule fois. Si vous souhaitez rechercher plusieurs correspondances dans une même chaîne, le premier ^ devrait être utilisé.
Dan Breslau
4
Il a dit qu'il voulait tout faire correspondre jusqu'à la première occurrence d'un point-virgule, alors j'ai supposé qu'il voulait dire dès le début de la chaîne.
Glenn Slaven
15

Essayer /[^;]*/

Google regex character classespour plus de détails.

Dan Breslau
la source
8

exemple de texte:

"this is a test sentence; to prove this regex; that is g;iven below"

Si, par exemple, nous avons l'exemple de texte ci-dessus, l'expression régulière /(.*?\;)/vous donnera tout jusqu'à la première occurrence de point-virgule ( ;), y compris le point-virgule:"this is a test sentence;"

poncius
la source
3
il n'est pas nécessaire de s'échapper ;car car ce n'est pas un caractère spécial regex. Le regroupement ()n'est pas également requis. Vous pouvez aller avec/.*?;/
Aliaksei Kliuchnikau
1
Oui, tu as bien raison. l'évasion ressemblait plus à "mieux vaut prévenir que guérir"
poncius
2
C'est la réponse que je cherchais. Alors le ? fait que le match se termine à la première occurrence? Quel est le nom de cette propriété (appelons-la) de l'expression rationnelle?
Parziphal
1
@Parziphal le ?personnage rend le match paresseux (correspondant aussi peu de fois que possible). Pensez aux regex correspondant aux personnages jusqu'au premier point-virgule, puis cela ne va pas plus loin car il abandonne (paresseux;))
derekantrican
5

ce n'est pas une solution regex, mais quelque chose d'assez simple pour la description de votre problème. Divisez simplement votre chaîne et obtenez le premier élément de votre tableau.

$str = "match everything until first ; blah ; blah end ";
$s = explode(";",$str,2);
print $s[0];

production

$ php test.php
match everything until first
ghostdog74
la source
5

Cela m'a été très utile car j'essayais de trouver comment faire correspondre tous les caractères d'une balise xml, y compris les attributs. Je rencontrais le problème "correspond à tout jusqu'à la fin" avec:

/<simpleChoice.*>/

mais a pu résoudre le problème avec:

/<simpleChoice[^>]*>/

après avoir lu ce post. Merci a tous.

Yardboy
la source
1
J'avais trouvé qu'il est beaucoup plus efficace d'analyser réellement (chaque langage ou framework a ses propres classes pour cela) html / xml à cause de son format machine, les regex sont pour le langage naturel.
Leon Fedotov
1
Agréable. J'ai utilisé cela pour corriger des documents xml avec des erreurs de syntaxe dans la <!DOCTYPE>balise. Puisque l'analyseur n'a pas pu le gérer.
Martin Schneider
5

Cela correspondra à la première occurrence uniquement dans chaque chaîne et ignorera les occurrences suivantes.

/^([^;]*);*/
mchid
la source
3

"/^([^\/]*)\/$/" travaillé pour moi, pour obtenir uniquement les meilleurs "dossiers" d'un tableau comme:

a/   <- this
a/b/
c/   <- this
c/d/
/d/e/
f/   <- this
sPooKee
la source
2

Vraiment un peu triste que personne ne vous ait donné la bonne réponse ...

En regex,? le rend non gourmand. Par défaut, l'expression régulière correspondra autant que possible (gourmand)

Ajoutez simplement un? et il sera non gourmand et correspondra le moins possible!

Bonne chance, j'espère que ça aide.

L1amm
la source
3
Cela dépend fortement de l' implémentation regex réelle et toutes les implémentations n'ont pas un mode non gourmand.
karatedog
0

Je l'ai trouvé

/^[^,]*,/

fonctionne bien.

',' étant le "délimiteur" ici.

BookerVII
la source