Les quantificateurs * + ? {m,n} sont gourmands par nature, c'est à dire qu'ils prennent le plus de caractères possibles. Il est possible de les rendre non-gourmands pour qu'ils prennent le moins de caractères possibles comme ceci: *? +? ?? {m,n}?.
On regarde la première partie ^(.*)(.*). Le groupe 1 capture la partie commune, le groupe 2 la partie différente.
Voyons un peu le déroulement des opérations.
Les deux quantificateurs * sont gourmands, c'est le premier rencontré (le plus à gauche) qui prendra tous les caractères possibles, le 2e se contente de ceux qui restent, c'est à dire aucun au premier essai. Mais si la suite de la pattern échoue, le 1er quantificateur rendra son dernier caractère (que prendra alors le 2e quantificateur) pour faire un nouvel essai. Si le reste de la pattern échoue encore, le 1er quantificateur rendra encore un caractère et ainsi de suite, jusqu'à ce que la suite de la pattern réussisse.
Disons que v2 est "abcdefghij" et v1 est "XYZ_abcdef".
groupe 1 | groupe 2 | reste de la pattern
---------------+---------------+-----------------------
1 abcdefghij | | echec
---------------+---------------+-----------------------
2 abcdefghi | j | echec
---------------+---------------+-----------------------
3 abcdefgh | ij | echec
---------------+---------------+-----------------------
4 abcdefg | hij | echec
---------------+---------------+-----------------------
5 abcdef | ghij | réussite
---------------+---------------+-----------------------
Ce mécanisme qui consiste à rendre des caractères pour essayer une autre possibilité s'appelle le backtracking (le retour sur ses traces). Il se déclenche lorsque la suite de la pattern échoue et s'interrompt dés qu'elle réussit (ou que toutes les possibilités ont été testées sans succés).
C'est la particularité des quantificateurs gourmands.
Les quantificateurs non-gourmands se comportent de manière inverse: ils prennent le moins de caractères possible et si la suite de la pattern échoue, ils prennent un caractère en plus et ainsi de suite jusqu'à ce que la suite de la pattern réussisse.
Voyons ce qui se passe aux étapes 4 et 5 pour la suite de la pattern:
groupe 1 | .*? | \1
-------------+--------------+--------------
4 abcdefg | | echec
+--------------+--------------
| X | echec
+--------------+--------------
| XY | echec
+--------------+--------------
| XYZ | echec
+--------------+--------------
| XYZ_ | echec
+--------------+--------------
| XYZ_a | echec
+--------------+--------------
| XYZ_ab | echec
+--------------+--------------
| XYZ_abc | echec
+--------------+--------------
| XYZ_abcd | echec
+--------------+--------------
| XYZ_abcde | echec
+--------------+--------------
| XYZ_abcdef | echec
-------------+--------------+--------------
5 abcdef | | echec
+--------------+--------------
| X | echec
+--------------+--------------
| XY | echec
+--------------+--------------
| XYZ | echec
+--------------+--------------
| XYZ_ | réussite
-------------+--------------+--------------
Donc quelque soit le contenu du premier groupe (la partie commune), puisque le quantificateur est non-gourmand dans cette partie \n.*?\1, le moteur de regex essayera de trouver \1 dés le début de la ligne, puis si ça ne marche pas il essayera aprés le premier caractère, puis le deuxième, puis le troisième jusqu'à ce qu'il réussisse.
Partager