Artigo Build·Desenvolvimento·13 min de leitura de leitura

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.

Vitor Morais

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(""); // 0

Por 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("") # 0

Em 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

Caracteres “especiais” como emojis contam diferente em string JS: "🎉".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); // 4

Tempo de leitura

Cálculo padrão: palavras ÷ velocidade de leitura. Velocidades típicas:

Velocidade de leitura por idioma e tipo de conteúdo
CritérioPalavras/min
Inglês — leitura casual220-250
Inglês — leitura técnica180-200
Português — casual180-220
Português — técnico150-180
Leitura em voz alta130-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

No MochaLabz, usamos 200 palavras/min como padrão. Considerando que muito do conteúdo é técnico (denso), o valor real pode ser mais próximo de 180. Mas 200 é conservador-otimista — leitor casual se sente bem quando termina o artigo no tempo prometido ou um pouco antes.

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"); // 4

Python: 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

Tempo de análise por tamanho de texto
CritérioTempo 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

Para textos gigantes (enciclopédias, logs, corpus de NLP), considere processamento em stream em Node.js (byline, split2) para não carregar tudo em memória. Para editor web, debounce suficiente. Para análise em batch (Jupyter, pipeline), Python com Pandas + Dask escala para milhões de documentos.

Bibliotecas populares (quando usar)

Bibliotecas para contagem e análise
CritérioQuando 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
TiktokenContagem 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.

#contar palavras#javascript#python#split#regex#tempo de leitura#editor#nlp#intl.segmenter

Artigos relacionados