Quelqu’un peut-il me dire pourquoi
System.out.println("test".replaceAll(".*", "a"));
Résulte en
aa
Notez que ce qui suit a le même résultat:
System.out.println("test".replaceAll(".*$", "a"));
Je l’ai testé sur java 6 et 7 et les deux semblent se comporter de la même manière. Est-ce que je manque quelque chose ou est-ce un bug dans le moteur de regex java?
Ce n’est pas une anomalie:. .*
Peut correspondre à n’importe quoi.
Vous demandez à remplacer toutes les occurrences:
.*
correspond également à une chaîne vide! Il correspond donc à une chaîne vide à la fin de l’entrée et la remplace par a
. Utiliser à la place .+
Ne présentera pas ce problème car cette regex ne peut pas correspondre à une chaîne vide (il faut au moins un caractère pour correspondre).
Ou, utilisez .replaceFirst()
pour ne remplacer que la première occurrence:
"test".replaceFirst(".*", "a") ^^^^^^^^^^^^
Maintenant, pourquoi .*
Se comporte comme il le fait et ne correspond pas plus de deux fois (cela pourrait théoriquement le faire) est une chose intéressante à considérer. Voir ci-dessous:
# Before first run regex: |.* input: |whatever # After first run regex: .*| input: whatever| #before second run regex: |.* input: whatever| #after second run: since .* can match an empty ssortingng, it it satisfied... regex: .*| input: whatever| # However, this means the regex engine matched an empty input. # All regex engines, in this situation, will shift # one character further in the input. # So, before third run, the situation is: regex: |.* input: whatever<|ExhaustionOfInput> # Nothing can ever match here: out
Notez que, comme @AH le note dans les commentaires, tous les moteurs de regex ne se comportent pas de cette façon. GNU sed
par exemple, considérera qu’il a épuisé les données après la première correspondance.