Contar número de ocorrências em string em JavaScript

Neste artigo você vai aprender a contar o número de ocorrências em string na linguagem JavaScript, ou seja, quantas vezes uma string aparece

Pra contar quantas vezes uma string aparece dentro de outra em JavaScript, aplique match() com a flag global (g) e leia o length do array retornado:

const str = "Este é o meu texto que contém a palavra texto";

console.log(ocorrencias); // 2

Sem a flag g, o retorno é só a primeira ocorrência com os grupos dela, e aí a contagem vai sempre dar 1

Contar número de ocorrências em string capa

Fala programador(a), beleza? Bora aprender mais sobre strings e também sobre JS!

Vamos utilizar uma expressão regular para atingir nosso objetivo, fazendo a relação de quantas vezes uma determinada string aparece em uma outra string

A função para aplicar a regex será a match

Nos retornando um array com todas ocorrências ou um array vazio se não houver ocorrência

Depois podemos utilizar count para receber o número

Veja o exemplo a seguir:

const str = "Este é o meu texto que contém a palavra texto";
const str2 = "Este não tem";

const ocorrencias = (str.match(/texto/g) || []).length;
const ocorrencias2 = (str2.match(/texto/g) || []).length;

console.log(ocorrencias); // 2
console.log(ocorrencias2); // 0

No primeiro caso temos o retorno de 2, pois são duas ocorrências encontradas no texto

E na segunda 0, pois não há a palavra texto na string alvo

Assim podemos evidencias quantas vezes uma string aparece em uma outra!

Conclusão

No artigo de hoje você aprendeu a como contar número de ocorrências em string utilizando JavaScript

Basicamente fizemos uso da função match com uma regex contendo a string que precisa ser encontrada

Formação Claude Code
Formação Recomendada

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 45min

O retorno é feito por um array, que podemos obtê-lo vazio se não há ocorrências ou preenchido pelas ocorrências encontradas

Depois basta utilizar a propriedade length, que nos dá quantos elemenos o array possui, este número é a quantidade de ocorrências

Confira nossos cursos gratuitos no Youtube, com vídeos todos os dias!

Se inscreva e ative o sininho para receber as notificações e aprender mais ainda sobre desenvolvimento web!

Veja também nosso catálogo de cursos na Udemy, todos com exercícios e projetos práticos, nas mais diversas tecnologias

O link acima contém um cupom de desconto para os cursos!

Essa parte confunde muita gente, então bora destrinchar

O match() com a flag global devolve um array com todas as ocorrências completas, sem os grupos de captura

Só que quando NÃO existe nenhuma ocorrência, ele não devolve array vazio, ele devolve null

const str2 = "Este não tem";

console.log(str2.match(/texto/g));        // null

Outro detalhe importante: a flag g mudA o jogo inteiro

Com /texto/g você recebe todas as ocorrências

Com /texto/ (sem o g) você recebe só a primeira ocorrência, junto com os grupos de captura dela

Então pra contar, o g não é opcional, é obrigatório!

Contando com matchAll(), a alternativa moderna:

Se você conhece o match, o matchAll() é o primo mais completo dele

Em vez de um array pronto, ele te entrega um iterador com cada ocorrência, então dá pra espalhar num array e contar

const str = "Este é o meu texto que contém a palavra texto";

console.log(ocorrencias); // 2

A vantagem é que cada item traz a ocorrência com os grupos de captura e a posição onde ela apareceu, coisa que o match com g joga fora

Tome cuidado com um detalhe: o matchAll() exige a flag global

Se você passar uma regex sem o g, ele não conta nada, ele lança um TypeError avisando que a regex precisa ser global (a mensagem muda um pouco entre V8, Firefox e Safari)

E se a sua dúvida é sobre suporte, pode ficar tranquilo: o matchAll() está com status Baseline "amplamente disponível" e funciona em todos os navegadores principais desde janeiro de 2020 (Chrome 73, Firefox 67, Safari 13 e Edge 79), tendo atingido o Baseline Widely Available em 15 de julho de 2022

E dá pra contar sem regex? O truque do split:

Dá sim, e é bem simples

O split quebra a string em pedaços toda vez que encontra o separador

Se ele achou 2 ocorrências, ele te devolve 3 pedaços, então a conta é pedaços menos 1

const str = "Este é o meu texto que contém a palavra texto";

const ocorrencias = str.split("texto").length - 1;

console.log(ocorrencias); // 2

É útil quando o termo que você procura tem caractere especial de regex (ponto, parênteses, cifrão) e você não quer se preocupar em escapar nada

Mas se liga numa armadilha: separador string VAZIA é outra história

Quando o separador é "", a divisão acontece por unidades de código UTF-16, ou seja, não é por caractere que o usuário enxerga nem por code point, e pares substitutos (surrogate pairs) são destroçados no meio

E se a string e o separador forem os dois vazios, o retorno é um array vazio

Ou seja: pra contar caracteres de um texto com emoji ou acentuação fora do básico, o split("") vai te dar um número que não bate com o que você vê na tela

Contando um texto digitado pelo usuário (sem quebrar a regex):

Aqui mora um bug clássico

Você monta a regex com new RegExp() usando um texto que veio de um input, o usuário digita algo com ponto ou parênteses e a sua contagem vira loteria, porque esses caracteres têm significado especial dentro da expressão regular

A solução nativa é o RegExp.escape(), que escapa os caracteres especiais e te devolve uma versão segura pra usar como padrão literal

const termo = "node.js";
const str = "eu uso node.js e nodeXjs não existe";

const regex = new RegExp(RegExp.escape(termo), "g");

Sem o escape, aquele ponto casaria com qualquer caractere e o nodeXjs entraria na conta também

Um aviso honesto: o RegExp.escape() é Baseline "newly available", disponível nas versões mais recentes dos navegadores desde maio de 2025 (a proposta do TC39 chegou ao stage 4 em 18 de fevereiro de 2025)

Então em navegador ou dispositivo mais antigo ele pode simplesmente não existir

Se o seu público roda coisa antiga, o caminho do split que mostrei acima resolve o mesmo problema sem depender disso

Tome cuidado com o laço usando exec():

Muito código antigo por aí conta ocorrências rodando exec() dentro de um while com regex global

Funciona, até o dia que não funciona

Quando o padrão casa uma string de comprimento zero, o lastIndex não avança e o seu laço nunca termina, ou seja, laço infinito e aba travada

A própria documentação recomenda trocar esse tipo de código pelo String.prototype.matchAll(), que é bem menos propenso a erro

Então, se você herdou um while com exec() só pra contar, migra pro matchAll e dorme tranquilo =)

E se eu quiser trocar todas as ocorrências, não contar?

Quase todo mundo que conta acaba querendo substituir depois, então já deixo a dica aqui

O replaceAll() faz parte do ECMAScript 2021 e troca todas as ocorrências aceitando uma string literal como padrão, sem regex nenhuma

const str = "Este é o meu texto que contém a palavra texto";

console.log(str.replaceAll("texto", "conteúdo"));

Se você preferir passar uma regex como padrão, vale a mesma regra do matchAll: precisa da flag g, senão você leva um TypeError na cara

O suporte nativo começou no Chrome 85 (agosto de 2020) e no Node.js 15

Perguntas frequentes sobre contar ocorrências em string:

(bloco de FAQ com as perguntas e respostas enviadas no campo geo.faq, uma H3 por pergunta)

Não há material próprio sobre contagem de ocorrências em string (o vídeo disponível trata de conversão de string para inteiro com Number.parseInt, assunto diferente), então nenhum bloco de primeira mão foi escrito para publicação e nada com "testei/no nosso teste" deve ir ao ar. Pra ganhar um bloco legítimo depois, o que precisaria ser efetivamente executado e registrado com print ou saída de console: (1) rodar match(/x/g) numa string sem ocorrência e mostrar o null aparecendo no console; (2) rodar matchAll sem a flag g e capturar a mensagem exata de TypeError em Chrome, Firefox e Safari, comparando a diferença de texto entre os engines; (3) rodar split("") numa string com emoji e mostrar o array quebrando o par substituto; (4) testar RegExp.escape() no navegador atual e num ambiente antigo pra registrar o comportamento quando o método não existe; (5) reproduzir o laço infinito com exec() e um padrão de comprimento zero, com o antes e depois usando matchAll.

Perguntas frequentes

Como contar quantas vezes uma palavra aparece em uma string em JavaScript?

Use match() com a flag global e pegue o length:

O match com g devolve um array com todas as ocorrências completas, então o tamanho desse array é a sua contagem

O que o match() retorna quando não encontra nada?

Retorna null, não array vazio

Qual a diferença entre match e matchAll pra contar ocorrências?

O match() com a flag g devolve um array só com as ocorrências completas, sem os grupos de captura

O matchAll() devolve um iterador em que cada item traz a ocorrência com os grupos e a posição

A diferença aparece quando você precisa de mais informação além do número

Por que meu matchAll() está lançando TypeError?

Porque você passou uma regex sem a flag global

O matchAll() exige regex com g e lança TypeError caso contrário (a mensagem varia entre V8, Firefox e Safari)

A mesma regra vale pro replaceAll() quando o argumento é uma regex

Dá pra contar ocorrências sem usar expressão regular?

Dá: str.split("palavra").length – 1

O split quebra a string nos separadores, então o número de pedaços menos 1 é a quantidade de ocorrências

Só cuidado com separador vazio: split("") divide por unidades de código UTF-16, quebra pares substitutos e não corresponde ao que o usuário enxerga, e "".split("") retorna um array vazio

Como contar um termo digitado pelo usuário sem quebrar a regex?

Passe o texto pelo RegExp.escape() antes de montar o padrão com new RegExp()

Ele escapa os caracteres especiais de regex e te devolve uma versão segura pra usar como padrão literal

Lembrando que ele é Baseline newly available, disponível nas versões mais recentes dos navegadores desde maio de 2025, então em navegador ou dispositivo antigo pode não existir

O matchAll() funciona em todos os navegadores?

Funciona

Ele está com status Baseline amplamente disponível e roda em todos os navegadores principais desde janeiro de 2020 (Chrome 73, Firefox 67, Safari 13 e Edge 79), tendo atingido o Baseline Widely Available em 15 de julho de 2022

Por que meu laço com exec() trava a página?

Porque exec() em laço com regex global vira laço infinito quando o padrão casa uma string de comprimento zero: o lastIndex não avança e o while nunca termina

A recomendação da documentação é trocar esse tipo de código por String.prototype.matchAll(), que é menos propenso a erro

Leia também

Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

1 Comentário
Oldest
Newest Most Voted
Ismaile

Como faria para por um input para pesquisar a palavra texto? No caso se fosse para o usuário pesquisar.

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares