200 votes

Différence entre .*? et. * pour regex

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'ai utilisé (.*?)< et <(.*?)> qui fonctionne bien, mais après avoir lu un peu dans regex, je commence tout juste à me demander pourquoi j'ai besoin de ? les expressions. Je ne l'ai fait que comme ça après les avoir trouvés sur ce site, donc je ne suis pas tout à fait sûr de la différence.

264voto

polygenelubricants Points 136838

Sur gourmand vs non-gourmand

La répétition dans la regex par défaut est gourmand: ils essaient de faire correspondre autant de répétitions que possible, et quand cela ne fonctionne pas et qu'ils ont à faire marche arrière, ils tentent de faire correspondre les moins de rep à la fois, jusqu'à ce qu'un match de l'ensemble du motif est trouvé. En conséquence, lorsqu'un match se passe enfin, une gourmande de répétition correspond comme beaucoup de répétitions que possible.

L' ? comme une répétition quantificateur change ce comportement en non-gourmand, aussi appelé réticents (par exemple Java) (et parfois "paresseux"). En revanche, cette répétition va d'abord essayer de mettre en ligne quelques répétitions que possible, et quand cela ne fonctionne pas et qu'ils ont à faire marche arrière, ils commencent correspondant à l'un des plus rept un temps. En conséquence, lorsqu'un match se passe enfin, malgré la répétition correspondent que peu de répétitions que possible.

Références


Exemple 1: De A à Z

Nous allons comparer ces deux modèles: A.*Z et A.*?Z.

Compte tenu de la manière suivante:

eeeAiiZuuuuAoooZeeee

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

Nous allons d'abord mettre l'accent sur ce qu' A.*Z n'. Quand elle correspondait à la première A, l' .*, étant gourmand, essaie d'abord de faire correspondre autant . que possible.

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

Depuis l' Z ne correspond pas, le moteur revient, et .* doit alors correspondre à un de moins .:

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

Cela se passe un peu plus de temps, jusqu'à ce que finalement nous arrivons à ceci:

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

Maintenant, Z peut correspondre, de sorte que le schéma d'ensemble correspond à:

eeeAiiZuuuuAoooZeeee
   \___________/
    A.*Z matched

En revanche, les réticents de la répétition en A.*?Z premiers matchs que quelques . que possible, et en prenant de plus . que nécessaire. C'est ce qui explique pourquoi il trouve deux matchs dans l'entrée.

Voici une représentation visuelle de ce que les deux modèles correspondants:

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

Exemple: Une alternative

Dans de nombreuses applications, les deux matches au-dessus de l'entrée est ce qui est souhaité, donc un peu réticents .*? est utilisé à la place de la goulue .* pour prévenir overmatching. Pour ce modèle particulier, cependant, il y a une meilleure alternative, aide nié de la classe de caractères.

Le modèle A[^Z]*Z retrouve également le même deux matchs à l' A.*?Z modèle pour la au-dessus de l'entrée (comme on le voit sur ideone.com). [^Z] est ce qu'on appelle un niée classe de personnage: elle correspond à rien, mais Z.

La principale différence entre les deux modèles est dans la performance: plus strictes, le caractère niées classe ne peut correspondre à un moyen pour une entrée donnée. Il n'a pas d'importance si vous utilisez avide ou réticents modificateur pour ce modèle. En fait, dans certaines saveurs, vous pouvez faire encore mieux et d'utiliser ce qui est appelé possessif quantificateur, ce qui ne veut pas revenir en arrière à tous.

Références


Exemple 2: De A à Z

Cet exemple devrait être illustratif: il montre comment le gourmand, réticents, et nié le caractère de classe de modèles de match différemment compte tenu de la même entrée.

eeAiiZooAuuZZeeeZZfff

Ce sont les matches au-dessus de l'entrée:

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

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

Rubriques connexes

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

Une gourmande de répétition peut outgreed un autre

228voto

Kobi Points 65357

C'est la différence entre gourmands et non-greedy.

tenir compte de la contribution 101000000000100

à l'aide de 1.*1, * gourmand - il match tout le chemin à la fin, et puis revenir en arrière jusqu'à ce qu'il corresponde 1, vous laissant avec 1010000000001.
.*? est non-greedy. * correspondra à rien, mais essayez de faire correspondre les caractères supplémentaires jusqu'à ce qu'il corresponde 1, finit par correspondance 101.

Tous les quantificateurs non-greedy mode: .*?, .+?, .{2,6}?, et même .??.

Dans votre cas, ce genre de comportements pourrait être <([^>]*)> - correspondant à autre chose qu'un signe supérieur.

42voto

Simon Points 5327

Disons que vous avez:

<a></a>

<(.*)> correspond a></a où que <(.*?)> correspond a. Ce dernier s'arrête après le premier match de l' >. Il vérifie la présence d'une ou 0 matches de .* , suivie par l'expression suivante.

La première expression <(.*)> ne s'arrête pas lors de l'appariement de la première >. Il continuera jusqu'à ce que le dernier match de l' >.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X