Guardé un objeto RegExp en una variable y lo usé para mapear una matriz de cadenas en una matriz de objetos (destinatarios de correo electrónico analizados), pero no funciona, como si un objeto RegExp no pudiera ejecutar su .exec() método más de una vez.
Sin embargo, si uso un literal de expresión regular en lugar del objeto almacenado, funciona según lo previsto.
No puedo entender la razón detrás de este comportamiento. ¿Se esperaba, o podría ser un error?
El código:
const pattern = /^\s*(?<name>\w.*?)?\W+(?<address>[a-zA-Z\d._-]+@[a-zA-Z\d._-]+\.[a-zA-Z\d_-]+)\W*$/gi; const input = "John Doe jdoe@acme.com; Ronald Roe <rroe@acme.com>"; const splitValues = input.split(/[\r\n,;]+/).map(s => s.trim()).filter(s => !!s); const matchGroups1 = splitValues.map(s => pattern.exec(s)); console.log('Using pattern RegExp object:', JSON.stringify(matchGroups1, null, 2)); const matchGroups2 = splitValues.map(s => /^\s*(?<name>\w.*?)?\W+(?<address>[a-zA-Z\d._-]+@[a-zA-Z\d._-]+\.[a-zA-Z\d_-]+)\W*$/gi.exec(s)); console.log('Using literal regular expression:', JSON.stringify(matchGroups2, null, 2));La salida:
[LOG]: "Using pattern RegExp object:", "[ [ "John Doe jdoe@acme.com", "John Doe", "jdoe@acme.com" ], null ]" [LOG]: "Using literal regular expression:", "[ [ "John Doe jdoe@acme.com", "John Doe", "jdoe@acme.com" ], [ "Ronald Roe <rroe@acme.com>", "Ronald Roe", "rroe@acme.com" ] ]"La diferencia radica en el indicador /g que ha pasado a ambas expresiones regulares. Desde MDN :
El método
RegExp.prototype.exec()con el indicadorgdevuelve cada coincidencia y su posición de forma iterativa.const str = 'fee fi fo fum'; const re = /\w+\s/g; console.log(re.exec(str)); // ["fee ", index: 0, input: "fee fi fo fum"] console.log(re.exec(str)); // ["fi ", index: 4, input: "fee fi fo fum"] console.log(re.exec(str)); // ["fo ", index: 7, input: "fee fi fo fum"] console.log(re.exec(str)); // null
Entonces /g en una expresión regular convierte el objeto de expresión regular en un tipo divertido de rastreador de estado mutable. Cuando llama a exec en una expresión regular /g , está haciendo coincidir y también configurando un parámetro en esa expresión regular que recuerda dónde se quedó para la próxima vez. La intención es que si coincide con la misma cadena, no obtendrá la misma coincidencia dos veces, lo que le permite hacer trucos mutables con bucles while similares a la forma en que escribiría una coincidencia de expresiones regulares global en Perl.
Pero dado que está haciendo coincidir dos cadenas diferentes, causa problemas. Veamos un ejemplo simplificado.
const re = /a/g; re.exec("ab"); // Fine, we match against "a" re.exec("ba"); // We start looking at the second character, so we match the "a" there. re.exec("ab"); // We start looking at the third character, so we get *no* match.Mientras que en el caso de que produzca la expresión regular cada vez, nunca verá este estado, ya que el objeto de expresión regular se crea de nuevo cada vez.
Entonces, el resumen es: no use /g si planea reutilizar la expresión regular contra varias cadenas.