Contar el número de coincidencias de una expresión regular en Javascript
98
Quería escribir una expresión regular para contar la cantidad de espacios / pestañas / nueva línea en un fragmento de texto. Así que ingenuamente escribí lo siguiente:
Por alguna razón desconocida, siempre vuelve 1. ¿Cuál es el problema con la declaración anterior? Desde entonces he resuelto el problema con lo siguiente: -
// THIS IS WHAT YOU NEEDconst count =(str)=>{const re =/YOUR_PATTERN_HERE/g
return((str ||'').match(re)||[]).length
}
Para aquellos que llegaron aquí buscando una forma genérica de contar el número de ocurrencias de un patrón de expresión regular en una cadena, y no quieren que falle si hay cero ocurrencias, este código es lo que necesita. He aquí una demostración:
/*
* Example
*/const count =(str)=>{const re =/[a-z]{3}/g
return((str ||'').match(re)||[]).length
}const str1 ='abc, def, ghi'const str2 ='ABC, DEF, GHI'
console.log(`'${str1}' has ${count(str1)} occurrences of pattern '/[a-z]{3}/g'`)
console.log(`'${str2}' has ${count(str2)} occurrences of pattern '/[a-z]{3}/g'`)
Esto funciona siempre que tenga al menos un espacio en su entrada. De lo contrario, match () devuelve molestamente null.
sfink
3
sfink tiene razón, definitivamente desea verificar si match () devolvió nulo:var result = text.match(/\s/g); return result ? result.length : 0;
Gras Double
37
También puede protegerse contra el nulo utilizando esta construcción:( str.match(...) || [] ).length
a'r
11
Como mencioné en mi respuesta anterior , puede usar RegExp.exec()para iterar sobre todas las coincidencias y contar cada ocurrencia; la ventaja se limita solo a la memoria, porque en general es aproximadamente un 20% más lento que el uso String.match().
var re =/\s/g,
count =0;while(re.exec(text)!==null){++count;}return count;
Creo que pusiste el || []en el lugar equivocado, debería ser('my string'.match(/\s/g) || []).length
woojoo666
0
Sin duda, esto es algo que tiene muchas trampas. Estaba trabajando con la respuesta de Paolo Bergantino y me di cuenta de que incluso eso tiene algunas limitaciones. Trabajar con representaciones de cadenas de fechas me pareció un buen lugar para encontrar rápidamente algunos de los problemas principales. Comience con una cadena de entrada como esta:
'12-2-2019 5:1:48.670'
y configura la función de Paolo así:
function count(re, str){if(typeof re !=="string"){return0;}
re =(re ==='.')?('\\'+ re): re;var cre =newRegExp(re,'g');return((str ||'').match(cre)||[]).length;}
Quería que se pasara la expresión regular, para que la función sea más reutilizable, en segundo lugar, quería que el parámetro fuera una cadena, para que el cliente no tenga que hacer la expresión regular, sino que simplemente coincida con la cadena, como un método de clase de utilidad de cadena estándar.
Ahora, aquí puede ver que estoy lidiando con problemas con la entrada. Con lo siguiente:
if(typeof re !=="string"){return0;}
Estoy asegurando que la entrada no es nada parecido a lo literal 0, false, undefined, o null, ninguno de los cuales son cadenas. Dado que estos literales no están en la cadena de entrada, no debería haber coincidencias, pero debería coincidir '0', que es una cadena.
Con lo siguiente:
re =(re ==='.')?('\\'+ re): re;
Estoy lidiando con el hecho de que el constructor de RegExp interpretará (creo que incorrectamente) la cadena '.'como el coincidente de todos los caracteres\.\
Finalmente, debido a que estoy usando el constructor RegExp, necesito darle la 'g'bandera global para que cuente todas las coincidencias, no solo la primera, similar a las sugerencias en otras publicaciones.
Me doy cuenta de que esta es una respuesta extremadamente tardía, pero podría ser útil para alguien que se tropieza por aquí. Por cierto, aquí está la versión de TypeScript:
function count(re: string, str: string): number {if(typeof re !=='string'){return0;}
re =(re ==='.')?('\\'+ re): re;const cre =newRegExp(re,'g');return((str ||'').match(cre)||[]).length;}
var result = text.match(/\s/g); return result ? result.length : 0;
( str.match(...) || [] ).length
Como mencioné en mi respuesta anterior , puede usar
RegExp.exec()
para iterar sobre todas las coincidencias y contar cada ocurrencia; la ventaja se limita solo a la memoria, porque en general es aproximadamente un 20% más lento que el usoString.match()
.fuente
Basado en https://stackoverflow.com/a/48195124/16777 pero corregido para que funcione en el caso de resultados cero.
fuente
('my string'.match(/\s/g) || []).length;
fuente
|| []
en el lugar equivocado, debería ser('my string'.match(/\s/g) || []).length
Sin duda, esto es algo que tiene muchas trampas. Estaba trabajando con la respuesta de Paolo Bergantino y me di cuenta de que incluso eso tiene algunas limitaciones. Trabajar con representaciones de cadenas de fechas me pareció un buen lugar para encontrar rápidamente algunos de los problemas principales. Comience con una cadena de entrada como esta:
'12-2-2019 5:1:48.670'
y configura la función de Paolo así:
Quería que se pasara la expresión regular, para que la función sea más reutilizable, en segundo lugar, quería que el parámetro fuera una cadena, para que el cliente no tenga que hacer la expresión regular, sino que simplemente coincida con la cadena, como un método de clase de utilidad de cadena estándar.
Ahora, aquí puede ver que estoy lidiando con problemas con la entrada. Con lo siguiente:
Estoy asegurando que la entrada no es nada parecido a lo literal
0
,false
,undefined
, onull
, ninguno de los cuales son cadenas. Dado que estos literales no están en la cadena de entrada, no debería haber coincidencias, pero debería coincidir'0'
, que es una cadena.Con lo siguiente:
Estoy lidiando con el hecho de que el constructor de RegExp interpretará (creo que incorrectamente) la cadena
'.'
como el coincidente de todos los caracteres\.\
Finalmente, debido a que estoy usando el constructor RegExp, necesito darle la
'g'
bandera global para que cuente todas las coincidencias, no solo la primera, similar a las sugerencias en otras publicaciones.Me doy cuenta de que esta es una respuesta extremadamente tardía, pero podría ser útil para alguien que se tropieza por aquí. Por cierto, aquí está la versión de TypeScript:
fuente
¿Qué tal esto?
fuente