web-dev-qa-db-fra.com

Quelle est la différence entre .*? et. * expressions régulières?

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.

117
Doug

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 >).

Voir Feuille de triche de quantificateur .

141
Kobi

Sur gourmand vs non-gourmand

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.

Les références


Exemple 1: de A à Z

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:

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

Exemple: une alternative

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.

Les références


Exemple 2: de A à ZZ

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:

Voici une représentation visuelle de ce à quoi ils correspondent:

         ___n
        /   \              n = negated character class
eeAiiZooAuuZZeeeZZfff      r = reluctant
  \_________/r   /         g = greedy
   \____________/g

Rubriques connexes

Ce sont des liens vers des questions et réponses sur stackoverflow qui couvrent certains sujets d’intérêt.

Une répétition gourmande peut surclassé une autre

150
polygenelubricants

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 >.

16
Simon