¿Cuál es el problema con esta expresión regular cuando uso el indicador global y el distintivo de mayúsculas y minúsculas? La 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"));
297
about 5 oct. 2009 a las 19:32

7 respuestas

La mejor respuesta

El objeto RegExp realiza un seguimiento de lastIndex donde se produjo una coincidencia, por lo que en las coincidencias posteriores comenzará desde el ú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 lastIndex a 0 después de cada prueba, simplemente elimine el indicador 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:

  1. Deje S ser el valor de ToString (cadena).
  2. Deje que la longitud sea la longitud de S.
  3. Permita que lastIndex sea el valor de la propiedad lastIndex.
  4. Permítame ser el valor de ToInteger (lastIndex).
  5. Si la propiedad global es falsa, sea i = 0.
  6. Si I <0 o I> length, establezca lastIndex en 0 y devuelva nulo.
  7. Llama a [[Match]], dándole los argumentos S e i. Si [[Partido]] error devuelto, vaya al paso 8; de lo contrario, sea r su resultado estatal y ve al paso 10.
  8. Deje i = i + 1.
  9. Ve al paso 6.
  10. Sea e el valor endIndex de r.
  11. Si la propiedad global es verdadera, establezca lastIndex en e.
  12. Sea n la longitud de la matriz de capturas de r. (Esto es lo mismo valor como 15.10.2.1's NCapturingParens.)
  13. Devuelve una nueva matriz con las siguientes propiedades:
    • El índice propiedad se establece en la posición de la subcadena coincidente dentro de la completa cadena S.
    • La propiedad de entrada está configurada a S.
    • La propiedad de longitud se establece en n + 1.
    • La propiedad 0 se establece en subcadena coincidente (es decir, la parte de S entre el desplazamiento i inclusive y offset e exclusivo).
    • Para cada entero i tal que I> 0 y yo ≤ n, establezca la propiedad denominada ToString (i) en el i-ésimo elemento de la matriz de capturas de r.
340
Code Maniac 9 feb. 2019 a las 06:05

Tenía 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. La operación slice se queja de un valor nulo. Supongo que esto se debe a re.lastIndex. Esto es extraño porque esperaría que se asigne un nuevo RegExp cada vez que se llama a la función y no se comparte entre múltiples invocaciones de mi función.

Cuando lo cambié a:

var re = new RegExp('^([^-]+)-([^-]+)-([^-]+)$', 'g');

Entonces no obtengo el efecto remanente lastIndex. Funciona como lo esperaría.

-1
Chelmite 28 jun. 2018 a las 23:05

Usar el indicador / g le dice que continúe buscando después de un golpe.

Si la coincidencia tiene éxito, el método exec () devuelve una matriz y actualiza las propiedades del objeto de expresión regular.

Antes de tu 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 ().

-1
Scott Schlechtleitner 21 sep. 2017 a las 00:33

Debe establecer re.lastIndex = 0 porque con g flag regex realiza un seguimiento de la última coincidencia ocurrida, por lo que la prueba no irá a probar la misma cadena, para eso debe hacer re.lastIndex = 0

var query = 'Foo B';
var re = new RegExp(query, 'gi');
var result = [];
result.push(re.test('Foo Bar'));
re.lastIndex=0;
result.push(re.test('Foo Bar'));

console.log(result)
0
jtate 28 ene. 2020 a las 18:46

Eliminar la bandera global g solucionará su problema.

var re = new RegExp(query, 'gi');

Debería ser

var re = new RegExp(query, 'i');
10
Jonatas Walker 25 nov. 2015 a las 20:41

RegExp.prototype.test actualiza la propiedad lastIndex de 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 lo invierte para que refleje el resultado.

Alternativamente, puede restablecer la propiedad lastIndex :

result.push(re.test('Foo Bar'));
re.lastIndex = 0;
result.push(re.test('Foo Bar'));
36
James 5 oct. 2009 a las 15:41

Está utilizando un solo objeto RegExp y lo está ejecutando varias veces. En cada ejecución sucesiva continúa desde el último índice de coincidencia.

Debe "restablecer" 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]

Dicho esto, puede ser más legible crear un nuevo objeto RegExp cada vez (la sobrecarga es mínima ya que RegExp se almacena en caché de todos modos):

result.push((/Foo B/gi).test(stringA));
result.push((/Foo B/gi).test(stringB));
70
Roatin Marth 5 oct. 2009 a las 15:40