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

j'essaie de diviser une chaîne en deux parties en utilisant regex. La chaîne est formatée comme suit:

text to extract<number>

j'ai utilisé (.*?)< et <(.*?)> qui fonctionnent bien mais après avoir lu dans regex un peu, je viens de commencer à me demander pourquoi j'ai besoin du ? dans les expressions. Je l'ai seulement fait comme ça après les avoir trouvés à travers ce site donc je ne suis pas vraiment sûr quelle est la différence.

90
demandé sur Rishabh 2010-06-19 14:16:59

3 réponses

c'est la différence entre les quantificateurs avides et non avides.

"1519170920 Considérer" l'entrée 101000000000100 .

en utilisant 1.*1 , * est cupide - il va correspondre tout le chemin jusqu'à la fin , puis revenir en arrière jusqu'à ce qu'il puisse correspondre 1 , vous laissant avec 1010000000001 .

.*? est le non-greedy. * ne correspondra à rien, mais essaiera de correspondre à des caractères supplémentaires jusqu'à ce qu'il corresponde 1 , correspondant finalement à 101 .

tous les quantificateurs ont un mode non-cupide: .*? , .+? , .{2,6}? , et même .?? .

dans votre cas, un motif similaire pourrait être <([^>]*)> - correspondant à tout sauf un plus grand-que le signe (à strictement parler, il correspond à zéro ou plusieurs caractères autres que > entre < et > ).

voir Quantificateur Feuille De Triche .

116
répondu Kobi 2016-11-21 07:43:22

Sur gourmand vs non-greedy

la répétition dans regex par défaut est greedy : ils essaient de faire correspondre autant de réps que possible, et quand cela ne fonctionne pas et ils doivent revenir en arrière, ils essaient de faire correspondre un rep de moins à la fois, jusqu'à ce qu'une correspondance de l'ensemble du modèle est trouvée. En conséquence, quand un match se produit finalement, une répétition gourmande correspondrait comme beaucoup reps que possible.

le ? comme un quantificateur de répétition change ce comportement en non-cupide , également appelé réticent ( en Java ) (et parfois"paresseux"). En revanche, cette répétition va d'abord essayer de faire correspondre comme peu reps que possible, et quand cela ne fonctionne pas et ils doivent revenir en arrière, ils commencent à correspondre un rept de plus par fois. Par conséquent, lorsqu'un match a finalement lieu, une répétition hésitante match comme quelques de répétitions que possible.

Références


exemple 1: de A à Z

comparons ces deux motifs: A.*Z et A.*?Z .

étant donné l'entrée suivante:

eeeAiiZuuuuAoooZeeee

Les modèles de rendement de la façon suivante:

concentrons-nous d'abord sur ce que A.*Z fait. Quand il correspond à la première A , le .* , étant cupide, tente d'abord de faire correspondre autant de . que possible.

eeeAiiZuuuuAoooZeeee
   \_______________/
    A.* matched, Z can't match

puisque le Z ne correspond pas, les retours de moteur, et .* doit alors correspondre à un de moins . :

eeeAiiZuuuuAoooZeeee
   \______________/
    A.* matched, Z still can't match

cela arrive encore quelques fois, jusqu'à ce que nous en arrivions finalement à ceci:

eeeAiiZuuuuAoooZeeee
   \__________/
    A.* matched, Z can now match

maintenant Z peut correspondre, donc le modèle général correspond:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

en revanche, la répétition hésitante dans A.*?Z correspond d'abord à peu de . que possible, et puis prendre plus de . si nécessaire. Cela explique pourquoi il trouve deux correspondances dans l'entrée.

Voici une représentation visuelle de ce que les deux motifs correspondaient:

eeeAiiZuuuuAoooZeeee
   \__/r   \___/r      r = reluctant
    \____g____/        g = greedy

exemple: une alternative

dans de nombreuses applications, les deux correspondances dans l'entrée ci-dessus c'est ce que l'on souhaite, donc un .*? réticent est utilisé à la place de l'avide .* pour éviter l'accumulation. Pour ce motif particulier, cependant, il y a une meilleure alternative, en utilisant la classe de caractères niés.

le motif A[^Z]*Z trouve aussi les deux mêmes correspondances que le motif A.*?Z pour l'entrée ci-dessus ( comme vu sur ideone.com ). [^Z] est ce qu'on appelle une classe de caractères niés : il correspond à tout sauf Z .

la principale différence entre les deux modèles est dans la performance: étant plus stricte, la classe de caractères niés ne peut correspondre qu'à une seule façon pour une entrée donnée. Cela n'a pas d'importance si vous utilisez des modificateurs Gourmands ou réticents pour ce motif. En fait, dans certaines saveurs, vous pouvez faire encore mieux et utiliser ce qui est appelé quantificateur possessif, qui ne recule pas du tout.

Références


exemple 2: de A à ZZ

cet exemple devrait être illustratif: il montre comment les modèles de classe de caractères avides, réticents, et niés correspondent différemment étant donné la même entrée.

eeAiiZooAuuZZeeeZZfff

ce sont les correspondances pour l'entrée ci-dessus:

Voici une représentation visuelle de ce qu'ils correspondaient:

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

rubriques Connexes

il s'agit de liens vers des questions et des réponses sur stackoverflow qui couvrent certains sujets qui peuvent être d'intérêt.

Une gourmande de répétition peut outgreed l'autre

131
répondu polygenelubricants 2017-05-23 11:55:05

disons que vous avez:

<a></a>

<(.*)> correspondrait à a></a<(.*?)> correspondrait à a . Ce dernier s'arrête après le premier match de > . Il vérifie la présence d'une ou 0 correspondances de .* suivies de l'expression suivante.

la première expression <(.*)> ne s'arrête pas à la première > . Elle se poursuivra jusqu'au dernier match de > .

15
répondu Simon 2010-06-19 10:20:06