J'essaie de scinder une chaîne en deux parties à l'aide de regex. La chaîne est formatée comme suit:
text to extract<number>
J'utilise (.*?)<
Et <(.*?)>
, mais après avoir lu un peu dans regex, je commence tout juste à me demander pourquoi j'ai besoin de ?
Dans les expressions . Je ne l'ai fait que comme ça après les avoir trouvés sur ce site, donc je ne suis pas sûr de la différence.
C'est la différence entre les quantificateurs gourmands et non-gourmands.
Considérons l'entrée 101000000000100
.
L'utilisation de 1.*1
, *
Est gourmande - elle correspond jusqu'à la fin, puis revient en arrière jusqu'à ce qu'elle puisse correspondre à 1
, Vous laissant avec 1010000000001
..*?
N'est pas gourmand. *
Ne correspondra à rien, mais essaiera ensuite de faire correspondre des caractères supplémentaires jusqu'à ce qu'il corresponde à 1
, Pour correspondre éventuellement à 101
.
Tous les quantificateurs ont un mode non gourmand: .*?
, .+?
, .{2,6}?
Et même .??
.
Dans votre cas, un modèle similaire pourrait être <([^>]*)>
- correspondant à tout sauf à un signe supérieur à (à proprement parler, il correspond à zéro ou plusieurs caractères autres que >
Entre-deux <
et >
).
La répétition dans une expression rationnelle par défaut est gourmande: ils essaient d'associer autant de représentants que possible, et lorsque cela ne fonctionne pas et qu'ils doivent revenir en arrière, ils essaient d'associer un représentant de moins à la fois. , jusqu'à ce qu'une correspondance de l'ensemble du motif soit trouvée. En conséquence, quand un match se produit finalement, une répétition gloutonne correspondra aussi = plusieurs autant que possible.
Le ?
en tant que quantificateur de répétition modifie ce comportement en non-glouton, également appelé réticent ( en Java, par exemple ) (et parfois "paresseux"). En revanche, cette répétition essaiera d’abord de faire correspondre le plus possible les représentants peu, et lorsque cela ne fonctionnera pas et qu’ils devront revenir en arrière, ils commenceront à faire correspondre une répétition supplémentaire à la fois. En conséquence, lorsqu'un match se produit finalement, une répétition réticente correspondra aussi = peu que possible.
Comparons ces deux modèles: A.*Z
et A.*?Z
.
Compte tenu de l'entrée suivante:
eeeAiiZuuuuAoooZeeee
Les modèles donnent les correspondances suivantes:
A.*Z
donne 1 correspondance: AiiZuuuuAoooZ
( voir sur rubular.com )A.*?Z
donne 2 correspondances: AiiZ
et AoooZ
( voir sur rubular.com )Voyons d'abord ce que A.*Z
Est-ce que. Quand il correspond au premier A
, le .*
, étant gourmand, essaie d’abord de faire correspondre autant de .
possible.
eeeAiiZuuuuAoooZeeee
\_______________/
A.* matched, Z can't match
Puisque Z
ne correspond pas, le moteur effectue un retour arrière et .*
doit alors correspondre à un de moins .
:
eeeAiiZuuuuAoooZeeee
\______________/
A.* matched, Z still can't match
Cela se produit encore quelques fois, jusqu'à ce que nous arrivions enfin à ceci:
eeeAiiZuuuuAoooZeeee
\__________/
A.* matched, Z can now match
Maintenant, Z
peut correspondre, donc le motif général correspond:
eeeAiiZuuuuAoooZeeee
\___________/
A.*Z matched
En revanche, la répétition réticente dans A.*?Z
le premier correspond à quelques .
_ possible, puis prendre plus de .
le cas échéant. Cela explique pourquoi il trouve deux correspondances dans l'entrée.
Voici une représentation visuelle de la correspondance entre les deux modèles:
eeeAiiZuuuuAoooZeeee
\__/r \___/r r = reluctant
\____g____/ g = greedy
Dans de nombreuses applications, les deux correspondances de la saisie ci-dessus correspondent à ce qui est souhaité, ainsi un .*?
est utilisé à la place du gourmand .*
pour éviter le sur-ajustement. Pour ce modèle particulier, cependant, il existe une meilleure alternative, en utilisant une classe de caractères annulée.
Le motif A[^Z]*Z
trouve également les deux mêmes correspondances que le A.*?Z
modèle pour l’entrée ci-dessus ( comme indiqué sur ideone.com ). [^Z]
est ce qu'on appelle une classe de caractères négated: elle correspond à tout sauf Z
.
La principale différence entre les deux modèles réside dans les performances: étant plus stricte, la classe de caractères annulée ne peut correspondre qu’à un seul moyen pour une entrée donnée. Peu importe que vous utilisiez un modificateur avide ou réticent pour ce motif. En fait, dans certaines versions, vous pouvez faire encore mieux et utiliser ce qu'on appelle un quantificateur possessif, qui ne fait aucun retour en arrière.
Cet exemple doit être illustratif: il montre comment les modèles de classe de caractères avides, réticents et niés correspondent différemment pour une même entrée.
eeAiiZooAuuZZeeeZZfff
Voici les correspondances pour l'entrée ci-dessus:
A[^Z]*ZZ
donne 1 correspondance: AuuZZ
( comme on le voit sur ideone.com )A.*?ZZ
donne 1 correspondance: AiiZooAuuZZ
( comme on le voit sur ideone.com )A.*ZZ
donne 1 correspondance: AiiZooAuuZZeeeZZ
( comme on le voit sur ideone.com )Voici une représentation visuelle de ce à quoi ils correspondent:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
Ce sont des liens vers des questions et réponses sur stackoverflow qui couvrent certains sujets d’intérêt.
Disons que vous avez:
<a></a>
<(.*)>
correspondrait à a></a
, où <(.*?)>
correspondrait à a
. Ce dernier s'arrête après le premier match de >
. Il recherche une ou 0 correspondance de .*
Suivie de l'expression suivante.
La première expression <(.*)>
ne s'arrête pas lors de la mise en correspondance du premier >
. Il continuera jusqu'à la dernière correspondance de >
.