2012-06-13 14 views
12

Duplicar posible:
Interesting test of Javascript RegExp
Regular expression test can't decide between true and false (JavaScript)¿Por qué el mismo RegExp se comporta de manera diferente?

Example of issue. Cuando se ejecutó en línea, los resultados son como esperaba. Pero cuando se almacena como una variable, omite el elemento de tramo medio.

// Inline RegExp 
function getToggleClasses() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    if (/toggler/g.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Inline: " + toggler.length; 
} 

// Variable 
function getToggleClasses2() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     tester = /toggler/g, 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    if (tester.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length; 
} 
​ 

Marque:

<span class="toggler">A</span> 
<span class="toggler">B</span> 
<span class="toggler">C</span> 

Dado: entiendo que no hay razón para usar una expresión regular para hacer esta comparación y también entender cómo grandes bibliotecas como jQuery son. También sé que el g no es necesario en este caso.

No puedo entender por qué estos dos métodos alguna vez deberían arrojar resultados diferentes.

+0

Esto es solo una preferencia personal, pero creo que mejoraría la claridad un poco para poner paréntesis alrededor de un literal de expresión regular que tiene indicadores al llamar a una función en el literal. – JAB

+1

@apsillers, tienes razón. ¿Qué buscabas para encontrar esos? No pude averiguar qué buscar para obtener los resultados que buscaba. – Joe

+0

Hice una trampa un poco y busqué '[javascript] regex test lastindex' - Estaba bastante seguro de que una pregunta como esta se había hecho antes, y sabía que la respuesta incluiría el texto' lastIndex'. Este es un buen caso que muestra que la existencia de una pregunta duplicada no es necesariamente una indicación de que el solicitante ha sido negligente; Has hecho una pregunta bien formulada para un problema difícil de buscar. – apsillers

Respuesta

9

RegExp casos son de estado, por lo que la reutilización de ellos puede provocar un comportamiento inesperado. En este caso particular, es porque la instancia es global, que significa:

que la expresión regular debe probarse con todas las posibles coincidencias en una cadena.

No obstante, esa no es la única diferencia causada por el uso de g. From RegExp.test @ MDN:

Al igual que con exec (o en combinación con ella), test llamado varias veces en la misma instancia global de expresiones regulares hará avanzar más allá del partido anterior.


Remove the g flag o set lastIndex to 0 (gracias, @zzzzBov).

+3

o establezca 'lastIndex' en' 0' ... – zzzzBov

+0

@zzzzBov buen punto, editado. –

3

/g es no necesarios y no debe utilizarse en este caso.

El comportamiento difiere en estos casos porque en el caso "en línea" el objeto regex se recrea cada iteración del ciclo. Mientras que en la variable se crea una vez, y mantiene su estado (lastIndex) entre iteraciones de bucle.

Mover el var en el bucle y obtendrá el mismo resultado:

// Variable 
function getToggleClasses2() { 
    var toggler = [], 
     elements = document.getElementsByTagName("*"), 
     i=0, 
     len = elements.length; 

    for (i; i < len; i++) { 
    var tester = /toggler/g; 
    if (tester.test(elements[i].className)) { 
     toggler.push(elements[i]); 
    } 
    } 

    document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length; 
} 
+1

Sí, tengo eso. Pero un por qué es lo que tengo mucha curiosidad por saber. Porque '/toggler/g.test('toggler '); // verdadero' – Joe

+1

@Joe, explicado. – Qtax

+1

@Joe, escribiste en la pregunta * "También sé que se necesita' g '"*, es por eso que afirmo que no. – Qtax

1

La expresión regular mantiene una variable llamada lastIndex, que es el índice para iniciar la siguiente búsqueda. De MDN:

Al igual que con exec (o en combinación con ella), test llamado varias veces en la misma instancia global de expresiones regulares hará avanzar más allá del partido anterior.

Cuando se define una expresión regular en línea para cada iteración, el estado está perdido y lastIndex siempre es 0 porque tiene una expresión regular de nuevo cada vez. Si mantiene la expresión regular en un veriable, el lastIndex se guarda como la posición final de la última coincidencia, que en este caso hace que la siguiente búsqueda comience al final de la siguiente cadena, lo que da como resultado una coincidencia fallida. Cuando llega la tercera comparación, el lastIndex se ha restablecido a 0 porque la expresión regular sabe que no obtuvo resultados la última vez.

Cuestiones relacionadas