2010-01-26 8 views
15

Tengo un problema extraño al trabajar con la función Javascript Regexp.exec. Cuando se llama varias veces a la función en objetos nuevos (supongo ...) regexp, funciona una vez cada dos. ¡No entiendo por qué!Javascript Regex literal con/g usado varias veces

Aquí hay un pequeño ejemplo de bucle pero hace lo mismo cuando se usa una vez en una función y se llama varias veces.

for (var i = 0; i < 5; ++i) { 
    console.log(i, (/(b)/g).exec('abc')); 
} 

> 0 ["b", "b"] 
> 1 null 
> 2 ["b", "b"] 
> 3 null 
> 4 ["b", "b"] 

Al quitar el/g, vuelve a la normalidad.

for (var i = 0; i < 5; ++i) { 
    console.log(i, (/(b)/).exec('abc')); 
}    /* no g^*/ 

> 0 ["b", "b"] 
> 1 ["b", "b"] 
> 2 ["b", "b"] 
> 3 ["b", "b"] 
> 4 ["b", "b"] 

Supongo que hay una optimización, guardando el objeto regexp, pero parece extraño.

Este comportamiento es el mismo en Chrome 4 y Firefox 3.6, sin embargo, funciona como (I) se espera en IE8. Creo que eso está destinado, pero no puedo encontrar la lógica allí, ¡quizás puedas ayudarme!

Gracias

+6

El mismo obj expresión regular está siendo reutilizado dentro de su bucle de allí, y '' lastIndex' restablece a 0' después de no coincidir con nada cada 2da iteración. Consulte http://stackoverflow.com/questions/1760192/which-way-is-better-to-define-javascript-regular-expressions/1760506#1760506 para obtener una gran captura de este "error". –

+1

Creo que este problema ya puede estar solucionado. Ya estoy obteniendo la salida correcta de ambas formas en moz, chrome y es decir. ¿Alguien puede dar alguna explicación para esto? –

Respuesta

15

/gis not intended to work for simple matching:

/g permite que coinciden con "global". Al usar el método replace(), especifique este modificador para reemplazar todas las coincidencias, en lugar de solo la primera.

me imagino internamente Javascript tiene el juego después de la captura, por lo que sería capaz de reanudar el juego y por lo tanto null es devuelto desde b ocurren sólo una vez en el tema. Compare:

for (var i = 0; i < 5; ++i) { 
    console.log(i +' ' + (/(b+)/g).exec("abbcb")); 
} 

devuelve:

0 bb,bb 
1 b,b 
2 null 
3 bb,bb 
4 b,b 
+0

Dependiendo de lo que signifique "coincidencia simple", la opción "g" tiene perfecto sentido con "exec". En este caso, por ejemplo, si la cadena de prueba tenía múltiples caracteres "b", la matriz de resultados tendría todos ellos. – Pointy

+0

@Pointy: simple como en "no reemplazar". Y como mi código indica claramente que no funciona de esta manera – SilentGhost

+0

OK, está equivocado. La bandera "g" es muy útil incluso cuando no se realiza una operación de "reemplazo".Por ejemplo, es posible que desee extraer todos los números de una oración: /(\d+)/g.exec(sentence). – Pointy

15

Si usted va a volver a utilizar la misma expresión regular de todos modos, lo saca del bucle y explícitamente restablecerla:

var pattern = /(b)/g; 
for (var i = 0; i < 5; ++i) { 
    pattern.lastIndex = 0; 
    console.log(i + ' ' + pattern.exec("abc")); 
} 
+0

Esta es probablemente la mejor manera de hacerlo, pero solo funciona si está configurando la expresión regular en una var y no usándola en línea como el póster (es decir. '(/(b)/g).lastIndex = 0' will * not * work) –

2

Gracias :)

Encontré un effet lado interesante, es posible hacer una variable estática (en sentido de C, global pero en visible desde la función) sin cierre!

function test() { 
    var static = /a/g; 
    if ('count' in static) { 
     static.count++; 
    } else { 
     static.count = 1; 
    } 
    console.log(static.count); 
    } 

    for (var i = 0; i < 5; ++i) { test(); } 
    1 
    2 
    3 
    4 
    5 

(Estoy haciendo una nueva respuesta, porque no podemos poner el código dentro de un comentario)

+0

Esto no es una sorpresa. Las secciones entre corchetes de código en construcciones como "for" loops NO son nuevos ámbitos léxicos en Javascript. En otras palabras, el efecto de la colocación de la instrucción "var" dentro del bucle es exactamente lo mismo que colocarlo en la cabecera del bloque de funciones circundante. – Pointy

+0

Esto actúa de manera diferente en IE, porque IE de cómo IE maneja la expresión regular de forma diferente. En Chrome/Safari/FF, las expresiones regex en línea se consideran globales aunque se definan localmente como una variable. En IE, cada uno se construye como una nueva expresión regular para que imprima 1 1 1 1 1 en lugar de 1 2 3 4 5 –

+0

Probablemente debería cambiar el nombre de la variable estática, 'estática' es una palabra reservada en JavaScript aunque sea actualmente no es una palabra clave – codebox