Contar o número de correspondências de um regex em Javascript
98
Eu queria escrever um regex para contar o número de espaços / tabulações / nova linha em um pedaço de texto. Então, eu ingenuamente escrevi o seguinte: -
// THIS IS WHAT YOU NEEDconst count =(str)=>{const re =/YOUR_PATTERN_HERE/g
return((str ||'').match(re)||[]).length
}
Para aqueles que chegaram aqui em busca de uma forma genérica de contar o número de ocorrências de um padrão regex em uma string e não querem que falhe se houver zero ocorrências, esse código é o que você precisa. Aqui está uma demonstração:
/*
* 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'`)
Isso funciona desde que você tenha pelo menos um espaço em sua entrada. Caso contrário, match () retorna irritantemente nulo.
afundar em
3
sfink está certo, você definitivamente deseja verificar se match () retornou null:var result = text.match(/\s/g); return result ? result.length : 0;
Gras Double
37
Você também pode se proteger contra o nulo usando esta construção:( str.match(...) || [] ).length
a'r
11
Conforme mencionado na minha resposta anterior , você pode usar RegExp.exec()para iterar todas as correspondências e contar cada ocorrência; a vantagem é limitada apenas à memória, porque no geral é cerca de 20% mais lento do que o uso String.match().
var re =/\s/g,
count =0;while(re.exec(text)!==null){++count;}return count;
Acho que você colocou || []no lugar errado, deveria ser('my string'.match(/\s/g) || []).length
woojoo666
0
Isso certamente é algo que tem muitas armadilhas. Eu estava trabalhando com a resposta de Paolo Bergantino, e percebendo que mesmo isso tem algumas limitações. Achei que trabalhar com representações de strings de datas é um bom lugar para encontrar rapidamente alguns dos principais problemas. Comece com uma string de entrada como esta:
'12-2-2019 5:1:48.670'
e configurar a função de Paolo assim:
function count(re, str){if(typeof re !=="string"){return0;}
re =(re ==='.')?('\\'+ re): re;var cre =newRegExp(re,'g');return((str ||'').match(cre)||[]).length;}
Eu queria que a expressão regular fosse passada, para que a função fosse mais reutilizável, em segundo lugar, eu queria que o parâmetro fosse uma string, para que o cliente não tivesse que fazer a regex, mas simplesmente corresponder na string, como um método de classe de utilitário de string padrão.
Agora, aqui você pode ver que estou lidando com problemas com a entrada. Com o seguinte:
if(typeof re !=="string"){return0;}
Eu estou garantindo que a entrada não é nada parecido com o literal 0, false, undefined, ou null, nenhum dos quais são strings. Como esses literais não estão na string de entrada, não deve haver correspondências, mas deve haver correspondência '0', que é uma string.
Com o seguinte:
re =(re ==='.')?('\\'+ re): re;
Estou lidando com o fato de que o construtor RegExp irá (eu acho, erroneamente) interpretar a string '.'como o combinador de todos os caracteres\.\
Finalmente, como estou usando o construtor RegExp, preciso dar a ele o 'g'sinalizador global para que conte todas as correspondências, não apenas a primeira, semelhante às sugestões em outras postagens.
Sei que essa é uma resposta extremamente tardia, mas pode ser útil para alguém que está tropeçando aqui. BTW, aqui está a versão do 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
Conforme mencionado na minha resposta anterior , você pode usar
RegExp.exec()
para iterar todas as correspondências e contar cada ocorrência; a vantagem é limitada apenas à memória, porque no geral é cerca de 20% mais lento do que o usoString.match()
.fonte
Com base em https://stackoverflow.com/a/48195124/16777, mas corrigido para realmente funcionar em caso de resultado zero.
fonte
('my string'.match(/\s/g) || []).length;
fonte
|| []
no lugar errado, deveria ser('my string'.match(/\s/g) || []).length
Isso certamente é algo que tem muitas armadilhas. Eu estava trabalhando com a resposta de Paolo Bergantino, e percebendo que mesmo isso tem algumas limitações. Achei que trabalhar com representações de strings de datas é um bom lugar para encontrar rapidamente alguns dos principais problemas. Comece com uma string de entrada como esta:
'12-2-2019 5:1:48.670'
e configurar a função de Paolo assim:
Eu queria que a expressão regular fosse passada, para que a função fosse mais reutilizável, em segundo lugar, eu queria que o parâmetro fosse uma string, para que o cliente não tivesse que fazer a regex, mas simplesmente corresponder na string, como um método de classe de utilitário de string padrão.
Agora, aqui você pode ver que estou lidando com problemas com a entrada. Com o seguinte:
Eu estou garantindo que a entrada não é nada parecido com o literal
0
,false
,undefined
, ounull
, nenhum dos quais são strings. Como esses literais não estão na string de entrada, não deve haver correspondências, mas deve haver correspondência'0'
, que é uma string.Com o seguinte:
Estou lidando com o fato de que o construtor RegExp irá (eu acho, erroneamente) interpretar a string
'.'
como o combinador de todos os caracteres\.\
Finalmente, como estou usando o construtor RegExp, preciso dar a ele o
'g'
sinalizador global para que conte todas as correspondências, não apenas a primeira, semelhante às sugestões em outras postagens.Sei que essa é uma resposta extremamente tardia, mas pode ser útil para alguém que está tropeçando aqui. BTW, aqui está a versão do TypeScript:
fonte
que tal assim
fonte