Como Contar Palavras em JavaScript e Python (2026): Guia Completo com Código
Contar palavras parece trivial até você topar com idiomas sem espaços, contrações, hifens, emojis e código embedado. Este guia cobre implementação em JavaScript e Python, casos de uso (editor, CMS, tempo de leitura), cálculo em tempo real e decisões de design em ferramentas reais.
Por Vitor Morais
Fundador do MochaLabz ·
Conte palavras online
Cole texto, veja palavras, caracteres, parágrafos e tempo de leitura — instantâneo.
Usar contador →Contar palavras programaticamente parece tarefa trivial — e é, na maioria dos contextos. Dois-três caracteres de código resolvem 95% dos casos. Os outros 5%, que envolvem textos multi-idioma, editores em tempo real, contagem que exclui código ou separação por frase, pedem conhecimento específico que raramente aparece em tutoriais básicos.
Este guia cobre o básico limpo (split simples), segue para casos reais com edge cases (emojis, idiomas asiáticos, hifens), mostra como calcular tempo de leitura, implementa contador em tempo real para editores e oferece código pronto em JavaScript e Python.
O método básico: split por espaços
A forma mais simples, funcionando em 90% dos textos em idiomas latinos:
// JavaScript
function contarPalavras(texto: string): number {
return texto.trim().split(/\s+/).filter(Boolean).length;
}
contarPalavras("Olá mundo, como você está?"); // 5
contarPalavras("Palavra-única"); // 1
contarPalavras(" Com espaços extras "); // 3
contarPalavras(""); // 0Por que cada parte:
trim(): remove espaços no início e no fim.split(/\\s+/): divide por um ou mais caracteres de espaço (incluindo tab, quebra de linha).filter(Boolean): remove strings vazias que aparecem quando o texto está vazio.
Python equivalente
def contar_palavras(texto: str) -> int:
return len(texto.split())
contar_palavras("Olá mundo, como você está?") # 5
contar_palavras(" Com espaços extras ") # 3
contar_palavras("") # 0Em Python, .split() sem argumentos já divide por qualquer whitespace e ignora os vazios — mais conciso que o JavaScript.
Contagem de caracteres
function contarCaracteres(texto: string, semEspacos = false): number {
if (semEspacos) return texto.replace(/\s/g, "").length;
return texto.length;
}
contarCaracteres("Olá mundo"); // 9
contarCaracteres("Olá mundo", true); // 8 (sem espaço)Dica
"🎉".length === 2 (par surrogate). Para contagem visual correta, use [...texto].length ou Intl.Segmenter.Contagem de parágrafos e sentenças
// Parágrafos: separados por linha em branco
function contarParagrafos(texto: string): number {
return texto.split(/\n\s*\n/).filter((p) => p.trim()).length;
}
// Sentenças: separadas por . ! ?
function contarSentencas(texto: string): number {
return texto.split(/[.!?]+/).filter((s) => s.trim()).length;
}
const texto = `Primeiro parágrafo. Com duas sentenças.
Segundo parágrafo. E uma sentença extra!`;
contarParagrafos(texto); // 2
contarSentencas(texto); // 4Tempo de leitura
Cálculo padrão: palavras ÷ velocidade de leitura. Velocidades típicas:
| Critério | Palavras/min |
|---|---|
| Inglês — leitura casual | 220-250 |
| Inglês — leitura técnica | 180-200 |
| Português — casual | 180-220 |
| Português — técnico | 150-180 |
| Leitura em voz alta | 130-150 |
function tempoDeLeitura(
texto: string,
palavrasPorMinuto = 200,
): { minutos: number; label: string } {
const palavras = contarPalavras(texto);
const minutos = Math.max(1, Math.ceil(palavras / palavrasPorMinuto));
return {
minutos,
label: `${minutos} min de leitura`,
};
}
const artigo = "...";
tempoDeLeitura(artigo, 200); // { minutos: 8, label: "8 min de leitura" }Contexto
Idiomas sem espaços: chinês, japonês, tailandês
Chinês, japonês e tailandês escrevem palavras consecutivas sem separador. Split por espaço conta o texto todo como 1 palavra. Solução: Intl.Segmenter(disponível em JS desde 2023):
function contarPalavrasMultiIdioma(texto: string): number {
const segmenter = new Intl.Segmenter(undefined, {
granularity: "word",
});
let count = 0;
for (const segment of segmenter.segment(texto)) {
if (segment.isWordLike) count++;
}
return count;
}
// Chinês
contarPalavrasMultiIdioma("我爱编程"); // 4 (个, 爱, 编, 程 segmentadas)
// Japonês
contarPalavrasMultiIdioma("私はコードを書きます"); // 5
// Português ainda funciona
contarPalavrasMultiIdioma("Olá mundo como vai"); // 4Python: com biblioteca dedicada por idioma
# pip install jieba (chinês), sudachipy (japonês)
import jieba
def contar_palavras_chines(texto: str) -> int:
palavras = jieba.lcut(texto)
return len([p for p in palavras if p.strip()])
# Para genérico: NLTK
# pip install nltk
from nltk.tokenize import word_tokenize
import nltk
nltk.download("punkt")
def contar_palavras_universal(texto: str) -> int:
return len(word_tokenize(texto))Ignorando código em texto técnico
Em blog técnico, contar palavras incluindo blocos de código inflam o número. Se você tem 2.000 palavras de prosa e 500 de código, a contagem que importa pro leitor é 2.000 (tempo de leitura de texto, não de interpretar código).
function contarPalavrasIgnorandoCodigo(texto: string): number {
const semBlocosDeCodigo = texto
.replace(/```[\s\S]*?```/g, "") // blocos markdown triplo backtick
.replace(/`[^`]+`/g, "") // código inline
.replace(/<pre[\s\S]*?<\/pre>/gi, "") // <pre> HTML
.replace(/<code[\s\S]*?<\/code>/gi, ""); // <code> HTML
return contarPalavras(semBlocosDeCodigo);
}Contador em tempo real (editor)
Para editores modernos (Notion, Google Docs), o contador atualiza a cada tecla. Em React:
"use client";
import { useState, useMemo } from "react";
export function Editor() {
const [texto, setTexto] = useState("");
const stats = useMemo(() => ({
palavras: contarPalavras(texto),
caracteres: texto.length,
caracteresSemEspacos: texto.replace(/\s/g, "").length,
paragrafos: contarParagrafos(texto),
tempoLeitura: tempoDeLeitura(texto),
}), [texto]);
return (
<div>
<textarea
value={texto}
onChange={(e) => setTexto(e.target.value)}
className="w-full min-h-96 p-4"
/>
<div className="text-sm text-gray-600 mt-2">
{stats.palavras} palavras · {stats.caracteres} caracteres · {" "}
{stats.paragrafos} parágrafos · {stats.tempoLeitura.label}
</div>
</div>
);
}Dica
useMemo evita recomputar stats a cada re-render se o texto não mudou. Para textos gigantes (50k+ palavras), adicione debounce de 300ms para não travar digitação. Em editores ricos (Tiptap, Slate), use os eventos nativos em vez de useEffect.Debounce para textos grandes
import { useState, useEffect } from "react";
function useDebouncedValue<T>(value: T, delay: number): T {
const [debounced, setDebounced] = useState(value);
useEffect(() => {
const timer = setTimeout(() => setDebounced(value), delay);
return () => clearTimeout(timer);
}, [value, delay]);
return debounced;
}
export function EditorGrande() {
const [texto, setTexto] = useState("");
const textoDebounced = useDebouncedValue(texto, 300);
const stats = useMemo(() => ({
palavras: contarPalavras(textoDebounced),
caracteres: textoDebounced.length,
}), [textoDebounced]);
// ...
}Casos de uso reais
1. Meta description (SEO)
const LIMITE_META = 160;
function validarMetaDescription(texto: string): {
valido: boolean;
sobrando: number;
} {
const chars = texto.length;
return {
valido: chars >= 120 && chars <= LIMITE_META,
sobrando: LIMITE_META - chars,
};
}2. Tweet / X post
const LIMITE_TWEET = 280;
function contarCaracteresTweet(texto: string): number {
// Twitter conta emojis como 2 caracteres
const arrayChars = [...texto];
const emojis = arrayChars.filter((c) => /\p{Emoji}/u.test(c)).length;
return arrayChars.length + emojis;
}
contarCaracteresTweet("Olá 🎉"); // 6 (4 + 2 do emoji)3. Contagem para faturamento (tradução)
Serviços de tradução cobram por palavra. Importante contar exato para orçamento:
function calcularOrcamentoTraducao(
texto: string,
precoPorPalavra: number,
): number {
const palavras = contarPalavras(texto);
return palavras * precoPorPalavra;
}
calcularOrcamentoTraducao(
"...",
0.30, // R$ 0,30 por palavra
);4. Análise de chat com LLM
Para LLMs, tokens importam mais que palavras (1 token ≈ 0,75 palavra em inglês; em português, 1 token ≈ 0,5-0,6 palavra). Se precisa estimar custo sem biblioteca de tokenização:
function estimarTokensPt(texto: string): number {
// Estimativa rough: 1 palavra em português ≈ 1,6 tokens
const palavras = contarPalavras(texto);
return Math.ceil(palavras * 1.6);
}
// Para contagem exata, use tiktoken:
// npm install @dqbd/tiktoken
import { encoding_for_model } from "@dqbd/tiktoken";
const encoder = encoding_for_model("gpt-4");
const tokens = encoder.encode(texto).length;Implementação completa: módulo reutilizável
// lib/text-stats.ts
export interface TextStats {
palavras: number;
caracteres: number;
caracteresSemEspacos: number;
paragrafos: number;
sentencas: number;
tempoLeitura: {
minutos: number;
label: string;
};
}
export function analisarTexto(
texto: string,
options: { wpm?: number; ignorarCodigo?: boolean } = {},
): TextStats {
const { wpm = 200, ignorarCodigo = false } = options;
const textoParaPalavras = ignorarCodigo
? texto
.replace(/```[\s\S]*?```/g, "")
.replace(/`[^`]+`/g, "")
: texto;
const palavras = textoParaPalavras.trim().split(/\s+/).filter(Boolean).length;
const caracteres = texto.length;
const caracteresSemEspacos = texto.replace(/\s/g, "").length;
const paragrafos = texto.split(/\n\s*\n/).filter((p) => p.trim()).length;
const sentencas = texto.split(/[.!?]+/).filter((s) => s.trim()).length;
const minutos = Math.max(1, Math.ceil(palavras / wpm));
return {
palavras,
caracteres,
caracteresSemEspacos,
paragrafos,
sentencas,
tempoLeitura: {
minutos,
label: `${minutos} min de leitura`,
},
};
}Performance: limite prático
| Critério | Tempo em JS moderno |
|---|---|
| 1.000 palavras | < 1 ms |
| 10.000 palavras | ~5 ms |
| 100.000 palavras | ~30-50 ms |
| 1.000.000 palavras (livro) | ~300-500 ms |
Vai mais fundo
Bibliotecas populares (quando usar)
| Critério | Quando usar |
|---|---|
| Código próprio (15 linhas) | Simples, 90% dos casos |
| textstat (Python) | Análise completa: Flesch, Gunning Fog, SMOG |
| readability (JS) | Equivalente JS de textstat |
| natural (JS NLP) | Tokenização avançada, stemming |
| NLTK / spaCy (Python) | NLP sério, múltiplos idiomas |
| Tiktoken | Contagem de tokens LLM exata |
Erros clássicos
- Esquecer trim(): conta palavra vazia no começo ou fim.
- Split por “ “ em vez de /\s+/: falha com tabs e múltiplos espaços.
- Contagem de caracteres em string com emoji: length conta surrogates.
- Recomputar a cada tecla em texto grande: trava editor. Debounce.
- Não ignorar código em blog técnico: tempo de leitura fica inflado.
- Velocidade de leitura genérica: 200 wpm para EN, 180 para PT-BR.
- Assumir que split funciona para todos idiomas: chinês e japonês precisam de Intl.Segmenter.
Contagem em uma frase
Contar palavras é 95% tarefa de 3 linhas de código (trim + split + length) e 5% sofisticação quando você topa com idiomas sem espaços, emojis, editores em tempo real ou código embedado. Conhecer onde cada caso se aplica evita bugs sutis e entrega ferramenta robusta com poucas linhas a mais.
Perguntas frequentes
Qual a forma mais simples de contar palavras em JavaScript?+
Para texto simples: texto.trim().split(/\s+/).length. O split por regex de espaços (\s+) cobre espaços, tabs e quebras de linha. O trim() evita contar espaços no início/fim como palavra. Funciona em 95% dos casos. Para textos com emoji, caracteres especiais e idiomas sem espaços (chinês, japonês), precisa abordagem mais sofisticada com Intl.Segmenter.
Como lidar com textos multi-idioma?+
Línguas como chinês, japonês e coreano não usam espaço para separar palavras. Split simples conta o texto inteiro como 1 palavra. Use Intl.Segmenter (suporte universal desde 2023) para segmentação precisa: new Intl.Segmenter(undefined, { granularity: 'word' }).segment(texto). Em Python, use bibliotecas dedicadas: jieba para chinês, sudachi para japonês, NLTK genérica.
Tempo de leitura é calculado a partir da contagem de palavras?+
Sim. A fórmula padrão é: minutos = palavras / 200 (velocidade média de leitura em inglês) ou palavras / 180 em português (palavras mais longas). Para conteúdo técnico, ajuste para 150 (mais denso, lento). Exemplo: texto de 1.500 palavras = ~8 minutos em PT-BR, ~7,5 min em EN. Mostrar tempo no topo do artigo melhora retenção — leitor decide se tem tempo antes de começar.
Devo contar palavras em tempo real no editor?+
Para editores grandes (CMS, Google Docs), sim. Usuário quer feedback imediato enquanto digita. Performance: contar 10.000 palavras leva <5ms em JS moderno — sem problema. Para 100k+ palavras (documento longo), use debounce de 300ms para evitar recálculo a cada tecla. Bibliotecas como Tiptap e Slate já oferecem contadores embutidos para editores rich text.
Como contar apenas palavras reais, ignorando código?+
Depende do contexto. Para contagem de palavras de texto que contém snippets de código (artigo técnico, documentação), remova blocos de código antes de contar: texto.replace(/```[\s\S]*?```/g, '').replace(/`[^`]+`/g, ''). Conta só prosa humana. Útil em CMS de blog técnico para não inflar contagem de palavras com código.
Palavras, caracteres e parágrafos — quando usar cada métrica?+
Palavras: tempo de leitura, SEO, critério editorial. Caracteres: limites de redes sociais (Twitter/X, SMS), meta tags (title 60, description 160). Parágrafos: estrutura visual, blocos para scroll. Sentenças: legibilidade (Flesch Score). Blog normalmente mostra: palavras + tempo de leitura. Editor de meta description: caracteres. Ferramenta de resumo: sentenças. Contexto decide.
Como lidar com hifenização e contrações?+
Contrações (don't, it's) são 1 palavra. Hifens (auto-parse, bem-vindo) variam por regra linguística. Para inglês, bibliotecas de tokenization (NLTK, spaCy) tratam corretamente. Para português, regra prática: tratar palavras hifenizadas como 1 (bem-vindo = 1 palavra, não 2). Split por /\s+/ já faz isso automaticamente. Se precisa de rigor linguístico, use biblioteca de NLP específica.
Existem bibliotecas prontas para contar palavras?+
Sim, mas geralmente overkill. Em JS: word-count (npm), count-word (simples). Em Python: len(text.split()) ou biblioteca textstat para mais métricas. Para funções simples, implementar é mais rápido que adicionar dependência. Para análise de legibilidade completa (Flesch, Gunning Fog, SMOG), bibliotecas dedicadas (textstat em Python, readability em JS) agregam valor.
Artigos relacionados
Quantas Palavras um Texto Precisa Ter para SEO (2026): Guia com Dados Reais
Tamanho ideal de conteúdo para SEO por tipo de página: blog, landing, produto, categoria. Com dados reais de estudos, benchmark por intenção e por que mais palavras nem sempre é melhor.
Densidade de Palavras-chave: O que é e Qual a Faixa Ideal para SEO (2026)
Densidade de keywords é métrica clássica de SEO. Aprenda a fórmula, a faixa ideal em 2026, por que o Google moderno (BERT, MUM) deu um passo além, como evitar keyword stuffing, onde posicionar suas keywords e como auditar antes de publicar.
Legibilidade de Texto (2026): Flesch, Gunning Fog, Índices e Como Aplicar para SEO
Guia completo de índices de legibilidade (Flesch, Flesch-Kincaid, Gunning Fog, SMOG): como funcionam, adaptação ao português, uso em SEO e passo a passo para melhorar textos.