A maior armadilha entre regex em JavaScript e Python é que os dois motores compartilham a maior parte da mesma sintaxe, então um padrão parece portável até que silenciosamente se comporte mal. JavaScript usa o sabor ECMAScript; Python usa seu próprio módulo re, mais próximo do PCRE. Eles concordam nos 80% comuns, depois divergem em âncoras, lookbehind, strings de substituição e Unicode. Este guia tabula todas as diferenças que realmente quebram o código, para que você possa escrever padrões que sobrevivam ao copiar e colar entre linguagens.
Se você já pegou um regex do Stack Overflow e viu ele funcionar em um runtime, mas lançar um erro ou retornar nada no outro, é por isso: a resposta foi escrita para um motor. Abaixo está o mapa completo, com exemplos e uma maneira rápida de testar o mesmo padrão em ambos os sabores antes de enviá-lo.
JavaScript vs Python Regex em Resumo#
Aqui está a versão resumida antes do mergulho profundo. Estas são as diferenças que causam bugs reais, não trivialidades.
| Recurso | JavaScript (ECMAScript) | Python (re) |
|---|---|---|
| Âncoras de início/fim de string | Nenhuma (^/$ apenas) | \A e \Z |
| Lookbehind | Fixo e variável (ES2018+) | Apenas largura fixa |
Quantificadores possessivos (a++) | Não suportado | Suportado (Python 3.11+) |
Grupos atômicos (?>...) | Não suportado | Suportado (Python 3.11+) |
| Sintaxe de grupo nomeado | (?<name>...) | (?P<name>...) |
| Referência posterior nomeada | \k<name> | (?P=name) |
| Referência de grupo na substituição | $1, $<name> | \1, \g<name> |
Flag . corresponde a nova linha | s (dotall) | re.DOTALL / re.S |
Escapes de propriedade Unicode \p{...} | Precisa da flag u ou v | Não nativo (use o módulo regex) |
Flags inline (?i) | Não suportado | Suportado |
| Tratamento Unicode padrão | Unidades de código UTF-16 | Unicode por padrão no re |
O restante deste artigo explica cada linha, por que é importante e como reescrever um padrão para funcionar em ambos.
Dica rápida: quando um padrão funciona em uma linguagem e não na outra, a causa é quase sempre âncoras, lookbehind ou sintaxe de substituição. Verifique esses três primeiro antes de assumir que a regex em si está errada.
Âncoras: a lacuna entre \A e \Z#
Este é o erro mais comum que causa o clássico "funciona em Python, quebra em JavaScript". Python suporta dois conjuntos de âncoras, JavaScript suporta apenas um.
Em Python, ^ e $ correspondem ao início e ao fim de cada linha quando a flag re.MULTILINE está ativada, enquanto \A e \Z sempre correspondem apenas ao início e ao fim absolutos de toda a string, independentemente das flags. Essa distinção permite escrever um validador de string inteira rigoroso que ignora o comportamento multilinha.
JavaScript não tem \A ou \Z. Ele oferece apenas ^ e $, cujo significado muda com base na flag m (multilinha). Portanto, um padrão Python como \A\d{4}\Z não tem um token equivalente direto em JavaScript.
// Python: re.match(r"\A\d{4}\Z", text)
// Equivalente em JavaScript (sem flag multilinha, então ^ e $ são para a string inteira):
/^\d{4}$/.test(text);
A solução é remover a flag m em JavaScript e usar ^/$ simples, que então ancoram a string inteira. O problema: o $ do JavaScript também pode corresponder logo antes de uma quebra de linha final. Para rigor absoluto no final da string, use $(?![\s\S]). Esquecer disso é como uma entrada multilinha passa por um validador que parecia à prova de falhas.
Lookbehind: Largura Fixa vs Variável#
Lookbehind é onde os dois sabores trocam de lugar, o que surpreende quem assume que Python é sempre o mecanismo mais capaz.
- JavaScript adicionou lookbehind no ES2018 e suporta lookbehind de largura fixa e variável.
(?<=\$\d+)e(?<=cat|elephant)funcionam. - O módulo Python
reintegrado suporta apenas lookbehind de largura fixa.(?<=cat|dog)funciona porque ambas as alternativas têm três letras, mas(?<=cat|elephant)gerare.error: look-behind requires fixed-width pattern.
Portanto, um lookbehind de largura variável que funciona perfeitamente em um navegador moderno lançará um erro em tempo de compilação no Python. Se você precisar de lookbehind variável em Python, instale o módulo de terceiros regex, que o suporta, ou reestruture o padrão para usar um grupo de captura em vez de um lookbehind.
# Falha no re do Python:
re.compile(r"(?<=USD |EUR )\d+") # comprimentos diferentes -> erro
# Solução alternativa: capture e referencie, ou preencha alternativas com largura igual
re.compile(r"(?:USD|EUR) (\d+)") # captura o número no grupo 1
Se você ainda está inseguro sobre como lookbehind e lookahead realmente se comportam, vale a pena ler os mecanismos mais profundos em nosso guia de regex lookahead e lookbehind antes de portar padrões entre linguagens.
Capture Group and Backreference Syntax#
Both engines support named groups, but the syntax differs, and this is a hard compile error rather than a silent mismatch.
JavaScript uses (?<name>...). Python uses (?P<name>...) with that extra P. Get them crossed and the pattern simply will not compile.
| Action | JavaScript | Python |
|---|---|---|
| Define named group | (?<year>\d{4}) | (?P<year>\d{4}) |
| Backreference inside pattern | \k<year> | (?P=year) or \1 |
| Numbered backreference | \1 | \1 |
Numbered backreferences (\1, \2) are identical in both, so they are the safest choice when you want one pattern string to run unchanged in both languages. The moment you reach for named groups, you must branch your pattern per engine.
Inline flags#
Python lets you set flags inside the pattern with (?i) for case-insensitive, (?m) for multiline, and so on, including the scoped form (?i:...). JavaScript historically did not support inline flag modifiers at all; flags went only on the literal (/pattern/i) or the RegExp constructor. Scoped inline modifiers (?i:...) are a newer ECMAScript addition and are not yet universal across runtimes, so do not rely on them for portable code.
Sintaxe da String de Substituição (o Bug Silencioso)#
Este é perigoso porque não gera erro. Ele apenas produz saída incorreta, o que é muito mais difícil de detectar em revisão do que uma falha.
Quando você referencia um grupo capturado em uma string de substituição, o JavaScript usa o cifrão e o Python usa uma barra invertida.
// JavaScript: $1 referencia o grupo 1, $<name> referencia um grupo nomeado
"2026-06-25".replace(/(\d{4})-(\d{2})/, "$2/$1"); // "06/2026-25"
# Python: \1 referencia o grupo 1, \g<name> referencia um grupo nomeado
re.sub(r"(\d{4})-(\d{2})", r"\2/\1", "2026-06-25") # "06/2026-25"
Se você colar uma string de substituição JavaScript com $1 no re.sub do Python, o Python trata $1 como os caracteres literais cifrão-um, e sua substituição insere silenciosamente $1 na saída em vez do valor capturado. Nenhum erro, apenas texto corrompido. O oposto também acontece: um \1 em uma substituição JavaScript é lido como escape e quebra.
Aviso: erros de sintaxe em strings de substituição não geram exceções. Sempre teste uma substituição com uma string de amostra real no idioma de destino, não apenas no padrão de correspondência.
A Flag Dotall e a Correspondência Multilinha#
Por padrão, . não corresponde a uma quebra de linha em nenhum dos mecanismos. Para mudar isso, os nomes das flags diferem.
- JavaScript: a flag
s(introduzida no ES2018), como em/foo.bar/s. - Python:
re.DOTALLou sua forma abreviadare.S, passada parare.compileou para a chamada da função.
O comportamento, uma vez ativado, é idêntico, mas o JavaScript anexa flags como letras após a barra de fechamento ou como o segundo argumento de RegExp, enquanto o Python passa constantes de flag combinadas com o operador OR bit a bit, como re.DOTALL | re.IGNORECASE.
Um hábito portável: evite confiar em . para cruzar linhas. Use a classe explícita [\s\S] em qualquer linguagem, que corresponde a qualquer caractere, incluindo quebras de linha, sem nenhuma flag. Esse único truque elimina uma das incompatibilidades de flags mais comuns entre linguagens.
Unicode: Escapes de Propriedade e Comportamento Padrão#
Unicode é onde os mecanismos mais divergem silenciosamente, e isso afeta mais fortemente entradas não ASCII.
JavaScript trata strings como unidades de código UTF-16 por padrão. Sem a flag u (Unicode), um caractere astral como um emoji são duas unidades de código, e . ou um quantificador podem corresponder à metade dele, produzindo caracteres ilegíveis. Adicionar a flag u faz a regex operar em pontos de código e desbloqueia escapes de propriedade Unicode como \p{Letter} e \p{Script=Greek}. A flag mais recente v estende isso ainda mais com operações de conjunto.
Strings em Python 3 são Unicode por padrão, então \w e \d já correspondem a letras e dígitos Unicode, a menos que você passe re.ASCII. No entanto, o módulo re nativo do Python não suporta escapes de propriedade \p{...}. Se você precisar de escapes de propriedade em Python, instale o módulo de terceiros regex, que os adiciona.
| Necessidade | JavaScript | Python re |
|---|---|---|
Corresponder por propriedade Unicode \p{L} | Flag u ou v | Não suportado (use módulo regex) |
| Correspondência correta por ponto de código | Requer flag u | Padrão |
| Caracteres de palavra apenas ASCII | Padrão sem u é parcial | Flag re.ASCII |
A conclusão prática: em JavaScript, defina a flag u sempre que sua entrada puder conter texto não ASCII. Em Python, espere \w/\d com reconhecimento Unicode por padrão, mas não use \p{...} a menos que tenha a biblioteca regex instalada.
Quantificadores Possessivos e Grupos Atômicos#
Esses são recursos de controle de retrocesso. Quantificadores possessivos (a++, a*+, a?+) e grupos atômicos ((?>...)) impedem que o motor faça retrocesso em uma seção correspondida, o que pode evitar retrocesso catastrófico em entradas adversárias. O re embutido do Python adicionou ambos a partir do Python 3.11. O ECMAScript regex do JavaScript não suporta nenhum dos dois.
Portanto, um padrão usando (?>...) ou a++ de uma base de código Python 3.11+ gera um erro de sintaxe no JavaScript. Para obter controle semelhante no JavaScript, você reescreve o padrão com um truque de lookahead mais backreference (mais difícil de ler) ou reestrutura a regex para ser inequívoca desde o início.
Como Testar o Mesmo Padrão em Ambos os Flavors#
A maneira confiável de evitar todas essas armadilhas é testar o padrão exato contra um texto de amostra real em cada flavor antes de confirmá-lo. Ler uma tabela de compatibilidade diz o que deveria acontecer; executar o padrão diz o que realmente acontece.
Etapa 1: Escreva o padrão uma vez e defina suas strings de teste#
Comece com o padrão e três a cinco entradas de amostra que cubram seus casos extremos: uma correspondência limpa, uma quase correspondência, um caso multilinha e um caso não ASCII, se relevante. Mantenha-os à sua frente para confirmar as correspondências visualmente.
Etapa 2: Execute-o no flavor JavaScript#
Cole o padrão e as amostras em um testador de regex multi-flavor gratuito configurado para o motor JavaScript. Confirme as correspondências, grupos de captura e qualquer saída de substituição. Observe especialmente o comportamento de âncoras e o tratamento de Unicode aqui.
Etapa 3: Mude o flavor para Python e execute novamente#
Altere o motor para Python e execute o padrão e as amostras idênticos novamente. Compare o número de correspondências e grupos capturados com o resultado do JavaScript. Uma diferença aqui é o seu bug de portabilidade, descoberto antes de chegar à produção.
Etapa 4: Corrija a divergência usando as tabelas acima#
Quando os resultados diferirem, mapeie o sintoma para a seção relevante: âncoras, lookbehind, sintaxe de grupo nomeado, string de substituição ou flags Unicode. Aplique a reescrita portável (grupos numerados, [\s\S] em vez de dotall, lookbehind de largura igual) e execute ambos novamente até que concordem.
Se parte do padrão estiver fazendo algo que você não consegue decodificar, colá-lo em um explicador de código em português claro pode detalhar cada token e sinalizar as partes específicas do motor, o que acelera a correção.
Escrevendo Regex Portátil: Uma Pequena Lista de Verificação#
Quando um padrão precisa funcionar tanto em JavaScript quanto em Python sem ramificações, mantenha-se no subconjunto comum:
- Use grupos numerados e retroreferências
\1, não grupos nomeados. - Use
[\s\S]em vez de depender da flag dotall para cruzar quebras de linha. - Mantenha lookbehinds de largura fixa para que o
redo Python os aceite. - Evite quantificadores possessivos e grupos atômicos.
- Evite
\A/\Ze escapes de propriedade\p{...}. - Teste substituições separadamente, já que
$1vs\1é uma falha silenciosa.
Para trabalhos de modelagem de dados onde você também precisa inspecionar a saída estruturada junto com suas correspondências, combinar o testador com um formatador JSON mantém os resultados das correspondências legíveis enquanto você depura.
Conclusão#
A divisão entre regex em javascript vs python raramente está na sintaxe que você vê; está nas quatro diferenças silenciosas que mudam o comportamento sem gerar erro: a falta das âncoras \A/\Z, lookbehind apenas de largura fixa no Python, a diferença entre $1 e \1 na substituição e o suporte a escapes de propriedades Unicode. Memorize essas quatro, opte pelo subconjunto portátil quando um padrão cruzar linguagens e teste o padrão exato em ambos os motores antes de confiar nele. Esse hábito transforma regex de um jogo de copiar e colar em algo que você pode mover com segurança entre seu front-end e seu back-end.
Perguntas Frequentes#
Por que minha regex funciona em Python, mas não em JavaScript?
As causas mais comuns são recursos exclusivos do Python no seu padrão: âncoras \A/\Z, lookbehind de comprimento variável, quantificadores possessivos, grupos atômicos ou grupos nomeados (?P<name>...). O sabor ECMAScript do JavaScript não suporta esses recursos, então o padrão gera um erro de sintaxe ou simplesmente não corresponde a nada. Reescreva usando o subconjunto portátil (grupos numerados, lookbehind de largura fixa, ^/$ simples) e teste em ambos os mecanismos.
O JavaScript suporta lookbehind como o Python?
Sim, e em um aspecto o JavaScript é mais capaz. Desde o ES2018, o JavaScript suporta lookbehind de largura fixa e variável, enquanto o módulo re embutido do Python só suporta lookbehind de largura fixa. Um lookbehind de comprimento variável como (?<=cat|elephant) funciona em JavaScript moderno, mas gera um erro no re do Python. Para lookbehind variável em Python, use o módulo de terceiros regex.
Qual é a diferença entre $1 e \1 em substituições de regex?
Eles referenciam o mesmo grupo capturado, mas cada um pertence a um mecanismo diferente. Strings de substituição em JavaScript usam $1 (e $<nome> para grupos nomeados), enquanto re.sub do Python usa \1 (e \g<nome>). Misturá-los não gera erro; insere os caracteres literais, corrompendo silenciosamente a saída. Sempre teste substituições com uma string de amostra real no idioma de destino.
Os sabores de regex do JavaScript e Python são compatíveis? Eles compartilham a maior parte da sintaxe, aproximadamente 80% comum, incluindo classes de caracteres, quantificadores, alternância e referências anteriores numeradas. Eles divergem em âncoras, largura do lookbehind, sintaxe de grupos nomeados, strings de substituição, flags inline, quantificadores possessivos e escapes de propriedades Unicode. Um padrão restrito ao subconjunto compartilhado funcionará inalterado em ambos; qualquer coisa além disso precisa de ramificação por mecanismo ou reescrita.
Como corresponder caracteres Unicode por propriedade em cada idioma?
Em JavaScript, ative a flag u (ou v) e use escapes de propriedade como \p{Letter} ou \p{Script=Greek}. O módulo re embutido do Python não suporta \p{...}, então instale o módulo de terceiros regex para obter escapes de propriedade. Por padrão, o re do Python 3 já torna \w e \d cientes de Unicode, enquanto o JavaScript precisa da flag u para correspondência correta de pontos de código.
Qual é a maneira mais rápida de encontrar a diferença entre dois sabores de regex? Execute o padrão exato e o mesmo conjunto de strings de amostra em um testador de regex com múltiplos sabores, alternando o mecanismo de JavaScript para Python e comparando contagens de correspondências e grupos capturados. Qualquer diferença na saída é seu bug de portabilidade, isolado antes de ser enviado. Isso é mais rápido e confiável do que raciocinar sobre tabelas de compatibilidade, pois mostra o comportamento real na sua entrada real.



