Effectivement, le résultat m'a laissé dubitatif, mais après recherche, il s'explique parfaitement.
Partons du code plus léger suivant:
Si on teste la même chose sans le modificateur "g", alors toutes les chaînes sont matchées: en effet, toutes contiennent une décimale quelque part et [0-9]+ est une regex validée si on trouve un ou plusieurs caractères consécutifs entre 0 et 9 (donc, un ou plusieurs chiffres à la suite).
Pourquoi le drapeau g (global match) invalide-t-il les chaines "2. 22.1 .4. .4x"?
Ce drapeau permet de faire "boucler" le test d'une regex, en partant de la position de la dernière occurrence trouvée précédemment.
En d'autres mots, si g est utilisé, la chaîne ne sera testée qu'à partir de la position "lastIndex". Cette position, initialement à 0 quand on crée l'objet RegExp, contient la position de fin de la dernière occurrence valide trouvée dans la dernière chaîne testée.
Source: StackOverflow
Ainsi:
• On crée l'objet reg (lastIndex=0)
• On teste la première chaîne '2', à partir de lastIndex (0): on trouve une correspondance ("2"), et lastIndex=1
• On teste la chaîne suivante '22', à partir de lastIndex (1): on trouve une correspondance ("2" le second chiffre), et lastIndex=2
• On teste la chaîne suivante '2', à partir de lastIndex (2): on ne trouve rien (lastIndex dépasse la longueur de la chaine), donc la regex ne match pas cette chaîne. Comme il n'y a pas d'occurrence trouvée dans cette chaîne, lastIndex=0
• On teste la chaîne suivante '2.1', à partir de lastIndex (0): on trouve une première correspondance ("2"), puis une seconde ("1") d'où lastIndex=3 (la position après ce "1" trouvé)
• On teste la chaîne suivante '2.12', à partir de lastIndex (3): on trouve une correspondance ("2") donc lastIndex=4
• On teste la chaîne suivante '22.1', à partir de lastIndex (4): on ne trouve (la position 4 est après le "1", en fin de chaine) donc lastIndex=0
etc
D'où les chaînes non matchées.
La solution du problème peut passer ou bien par l'abandon du modificateur g s'il n'est pas nécessaire (à toi de savoir s'il l'est en fonction de tes besoins) ou bien par la réinitialisation manuelle de la valeur lastIndex en insérant reg.lastIndex = 0; avant le test reg.test().
Partons du code plus léger suivant:
var reg=/[0-9]+/g;
var tests = ['2', '22', '2', '2.1', '2.12', '22.1', '22.22', 'abc4e', '.4.', 'd4.', '.x4', '.4x'];
for (k=0,s=tests.length;k<s;++k)
{
console.log(reg.lastIndex, ' # ', tests[k]);
document.write('<br /><font style="color:'+ (reg.test(tests[k])? 'green': 'red') +';">'+tests[k]+'</font>');
//document.write("<br/>[color="+ (reg.test(tests[k])? 'green': 'red') +']'+tests[k]+'[/color]');
}
Résultat a écrit :2
22
2.
2.1
2.12
22.1
22.22
abc4e
.4.
d4.
.x4
.4x
Si on teste la même chose sans le modificateur "g", alors toutes les chaînes sont matchées: en effet, toutes contiennent une décimale quelque part et [0-9]+ est une regex validée si on trouve un ou plusieurs caractères consécutifs entre 0 et 9 (donc, un ou plusieurs chiffres à la suite).
Pourquoi le drapeau g (global match) invalide-t-il les chaines "2. 22.1 .4. .4x"?
Ce drapeau permet de faire "boucler" le test d'une regex, en partant de la position de la dernière occurrence trouvée précédemment.
En d'autres mots, si g est utilisé, la chaîne ne sera testée qu'à partir de la position "lastIndex". Cette position, initialement à 0 quand on crée l'objet RegExp, contient la position de fin de la dernière occurrence valide trouvée dans la dernière chaîne testée.
Source: StackOverflow
Ainsi:
• On crée l'objet reg (lastIndex=0)
• On teste la première chaîne '2', à partir de lastIndex (0): on trouve une correspondance ("2"), et lastIndex=1
• On teste la chaîne suivante '22', à partir de lastIndex (1): on trouve une correspondance ("2" le second chiffre), et lastIndex=2
• On teste la chaîne suivante '2', à partir de lastIndex (2): on ne trouve rien (lastIndex dépasse la longueur de la chaine), donc la regex ne match pas cette chaîne. Comme il n'y a pas d'occurrence trouvée dans cette chaîne, lastIndex=0
• On teste la chaîne suivante '2.1', à partir de lastIndex (0): on trouve une première correspondance ("2"), puis une seconde ("1") d'où lastIndex=3 (la position après ce "1" trouvé)
• On teste la chaîne suivante '2.12', à partir de lastIndex (3): on trouve une correspondance ("2") donc lastIndex=4
• On teste la chaîne suivante '22.1', à partir de lastIndex (4): on ne trouve (la position 4 est après le "1", en fin de chaine) donc lastIndex=0
etc
D'où les chaînes non matchées.
La solution du problème peut passer ou bien par l'abandon du modificateur g s'il n'est pas nécessaire (à toi de savoir s'il l'est en fonction de tes besoins) ou bien par la réinitialisation manuelle de la valeur lastIndex en insérant reg.lastIndex = 0; avant le test reg.test().