test - regexp javascript
¿Por qué un RegExp con marca global da resultados incorrectos? (6)
El objeto RegExp
realiza un seguimiento del último índice en el que se produjo una coincidencia, por lo que en las posteriores se iniciará a partir del último índice utilizado, en lugar de 0. Eche un vistazo:
var query = ''Foo B'';
var re = new RegExp(query, ''gi'');
var result = [];
result.push(re.test(''Foo Bar''));
alert(re.lastIndex);
result.push(re.test(''Foo Bar''));
Si no desea restablecer manualmente el lastIndex
a 0 después de cada prueba, simplemente elimine la lastIndex
g
.
Aquí está el algoritmo que dictan las especificaciones (sección 15.10.6.2):
RegExp.prototype.exec (cadena)
Realiza una coincidencia de expresión regular de cadena contra la expresión regular y devuelve un objeto Array que contiene los resultados de la coincidencia, o nulo si la cadena no coincide. La cadena ToString (cadena) busca una aparición del patrón de expresión regular de la siguiente manera:
- Sea S el valor de ToString (cadena).
- Sea la longitud la longitud de S.
- Deje que lastIndex sea el valor de la propiedad lastIndex.
- Sea i el valor de ToInteger (lastIndex).
- Si la propiedad global es falsa, sea i = 0.
- Si I <0 o I> longitud, establezca lastIndex en 0 y devuelva nulo.
- Llame a [[Match]], dándole los argumentos S e i. Si [[Match]] devolvió el error, vaya al paso 8; de lo contrario, r sea el resultado de su estado y vaya al paso 10.
- Sea i = i + 1.
- Vaya al paso 6.
- Sea e el valor del índice final de e.
- Si la propiedad global es verdadera, establezca lastIndex en e.
- Sea n la longitud de la matriz de capturas de r. (Este es el mismo valor que 15.10.2.1''s NCapturingParens.)
- Devuelve una nueva matriz con las siguientes propiedades:
- La propiedad de índice se establece en la posición de la subcadena coincidente dentro de la cadena completa S.
- La propiedad de entrada se establece en S.
- La propiedad de longitud se establece en n + 1.
- La propiedad 0 se establece en la subcadena coincidente (es decir, la parte de S entre offset i inclusive y offset e exclusive).
- Para cada entero i tal que I> 0 y I ≤ n, establezca la propiedad denominada ToString (i) en el elemento i de la matriz de capturas de r.
¿Cuál es el problema con esta expresión regular cuando uso la bandera global y la bandera que no distingue entre mayúsculas y minúsculas? Consulta es una entrada generada por el usuario. El resultado debe ser [verdadero, verdadero].
var query = ''Foo B'';
var re = new RegExp(query, ''gi'');
var result = [];
result.push(re.test(''Foo Bar''));
result.push(re.test(''Foo Bar''));
// result will be [true, false]
var reg = /^a$/g;
for(i = 0; i++ < 10;)
console.log(reg.test("a"));
El uso del indicador / g le indica que continúe buscando después de un golpe.
Antes de su primera búsqueda:
myRegex.lastIndex
//is 0
Después de la primera búsqueda
myRegex.lastIndex
//is 8
Elimine la g y sale de la búsqueda después de cada llamada a exec ().
Eliminar la bandera global g
solucionará tu problema.
var re = new RegExp(query, ''gi'');
Debiera ser
var re = new RegExp(query, ''i'');
Está utilizando un solo objeto RegExp
y ejecutándolo varias veces. En cada ejecución sucesiva continúa desde el último índice de coincidencia.
Debe "reiniciar" la expresión regular para comenzar desde el principio antes de cada ejecución:
result.push(re.test(''Foo Bar''));
re.lastIndex = 0;
result.push(re.test(''Foo Bar''));
// result is now [true, true]
Habiendo dicho que puede ser más legible crear un nuevo objeto RegExp cada vez (la sobrecarga es mínima ya que el RegExp se almacena en caché de todos modos):
result.push((/Foo B/gi).test(stringA));
result.push((/Foo B/gi).test(stringB));
Tuve la función:
function parseDevName(name) {
var re = /^([^-]+)-([^-]+)-([^-]+)$/g;
var match = re.exec(name);
return match.slice(1,4);
}
var rv = parseDevName("BR-H-01");
rv = parseDevName("BR-H-01");
La primera llamada funciona. La segunda llamada no lo hace. La operación de slice
queja de un valor nulo. Supongo que esto es debido al re.lastIndex
. Esto es extraño porque esperaría que se asignara un nuevo RegExp
cada vez que se llame a la función y no se comparta a través de múltiples invocaciones de mi función.
Cuando lo cambié a
var re = new RegExp(''^([^-]+)-([^-]+)-([^-]+)$'', ''g'');
Entonces no obtengo el lastIndex
efecto de lastIndex
. Funciona como lo esperaría.
RegExp.prototype.test
actualiza la propiedad lastIndex
las expresiones regulares para que cada prueba comience donde se detuvo la última. Sugeriría usar String.prototype.match
ya que no actualiza la propiedad lastIndex
:
!!''Foo Bar''.match(re); // -> true
!!''Foo Bar''.match(re); // -> true
Nota: !!
lo convierte en booleano y luego invierte el booleano para que refleje el resultado.
Alternativamente, puedes simplemente restablecer la propiedad lastIndex
:
result.push(re.test(''Foo Bar''));
re.lastIndex = 0;
result.push(re.test(''Foo Bar''));