Quais caracteres especiais devem ser escapados em expressões regulares?

389

Estou cansado de sempre tentar adivinhar, se devo escapar de caracteres especiais como ' ()[]{}|' etc. ao usar muitas implementações de regexps.

É diferente com, por exemplo, Python, sed, grep, awk, Perl, renomear, Apache, find e assim por diante. Existe algum conjunto de regras que diga quando devo e quando não devo escapar de caracteres especiais? Depende do tipo de regexp, como PCRE, POSIX ou regexps estendidos?

Igor Katson
fonte
4
Boas bibliotecas de regex têm funções como " escape()" para permitir o uso de seqüências arbitrárias como partes de regex.
ivan_pozdeev
2
Você pode usar os verificadores de expressão Regex online como gskinner.com/RegExr (é grátis). (Digite, em seguida, passe o mouse sobre o regex você digitou na)
hexicle
2
Escape de todos os caracteres não alfanuméricos. período.
Salman von Abbas
2
Esta pergunta foi adicionada às Perguntas frequentes sobre a expressão regular de estouro de pilha , em "Outros".
precisa saber é o seguinte
11
Esta pergunta foi adicionada às Perguntas frequentes sobre a expressão regular de estouro de pilha , em "Sequências de escape".
precisa saber é o seguinte

Respostas:

365

Quais caracteres você deve e quais não deve escapar realmente dependem do sabor da expressão regular com a qual você está trabalhando.

Para PCRE e a maioria dos outros tipos de sabores compatíveis com Perl, escape dessas classes de caracteres externas:

.^$*+?()[{\|

e estas classes de personagem internas:

^-]\

Para regex estendido POSIX (ERE), escape destas classes de caracteres externas (o mesmo que PCRE):

.^$*+?()[{\|

Escapar de qualquer outro caractere é um erro no POSIX ERE.

Dentro das classes de caracteres, a barra invertida é um caractere literal nas expressões regulares do POSIX. Você não pode usá-lo para escapar de nada. Você precisa usar "posicionamento inteligente" se quiser incluir metacaracteres da classe de caracteres como literais. Coloque o ^ em qualquer lugar, exceto no início, o] no início e - no início ou no final da classe de personagem para corresponder literalmente a eles, por exemplo:

[]^-]

Nas expressões regulares regulares do POSIX (BRE), esses são metacaracteres dos quais você precisa escapar para suprimir seu significado:

.^$*[\

Escapar parênteses e colchetes nos BREs dá a eles o significado especial que suas versões sem escape têm nos EREs. Algumas implementações (por exemplo, GNU) também dão um significado especial a outros caracteres quando escapados, como \? e +. Escapar de um caractere diferente de. ^ $ * () {} Normalmente é um erro nos BREs.

Dentro das classes de personagem, os BREs seguem a mesma regra dos EREs.

Se tudo isso fizer sua cabeça girar, pegue uma cópia do RegexBuddy . Na guia Criar, clique em Inserir token e, em seguida, literal. O RegexBuddy adicionará escapes conforme necessário.

Jan Goyvaerts
fonte
11
Parece-me que você esqueceu o "/", que também precisa ser escapado fora de uma classe.
precisa saber é o seguinte
11
/não é um metacaractere em nenhum dos sabores de expressões regulares que eu mencionei, portanto, a sintaxe da expressão regular não requer escapamento. Quando uma expressão regular é citado como um literal em uma linguagem de programação, em seguida, as regras de cordas ou regex formatação de que a linguagem pode exigir /ou "ou 'a ser escapou, e podem até mesmo exigir `\` a ser duplamente escapou.
Jan Goyvaerts
2
e quanto ao cólon ":"? Deve ser escapado dentro das classes de personagens e também fora? en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions diz que "PCRE possui regras de escape consistentes: qualquer caractere não alfanumérico pode ser escapado para significar seu valor literal"
nicolallias
4
Pode ser escapado não é o mesmo que deve ser escapado. A sintaxe PCRE nunca exige que dois pontos literais sejam escapados, portanto, escapar dois pontos literais apenas torna seu regex mais difícil de ler.
Jan Goyvaerts
11
Para ERE não POSIX (o que eu uso com mais frequência porque é implementado pelo Tcl), escapar de outras coisas não gera erros.
Slebetman
61

Sabores RegEx modernos (PCRE)

Inclui C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Real Studio, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo, XRegExp.
A compatibilidade do PCRE pode variar

    Qualquer lugar: . ^ $ * + - ? ( ) [ ] { } \ |


Sabores RegEx herdados (BRE / ERE)

Inclui awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
O suporte PCRE pode ser ativado em versões posteriores ou usando extensões

ERE / awk / egrep / emacs

    Fora de uma classe de personagem: . ^ $ * + ? ( ) [ { } \ |
    Dentro de uma classe de personagem:^ - [ ]

BRE / ed / grep / sed

    Fora de uma classe de caracteres: . ^ $ * [ \
    Dentro de uma classe de caracteres: ^ - [ ]
    Para literais, não escape: + ? ( ) { } |
    Para o comportamento regular da expressão regular, escape:\+ \? \( \) \{ \} \|


Notas

  • Se não tiver certeza sobre um caractere específico, ele pode ser escapado como \xFF
  • Caracteres alfanuméricos não podem ser escapados com uma barra invertida
  • Símbolos arbitrários podem ser escapados com uma barra invertida no PCRE, mas não BRE / ERE (eles devem ser escapados apenas quando necessário). Para o PCRE, ] -é necessário apenas escapar dentro de uma classe de personagem, mas eu os mantive em uma única lista para simplificar
  • As cadeias de expressão entre aspas também devem ter os caracteres de aspas circundantes escapados e, geralmente, com barras invertidas dobradas para cima (como "(\")(/)(\\.)"versus /(")(\/)(\.)/em JavaScript)
  • Além de escapes, diferentes implementações de regex podem suportar diferentes modificadores, classes de caracteres, âncoras, quantificadores e outros recursos. Para mais detalhes, consulte a regular-expressions.info , ou usar regex101.com para testar suas expressões viver
Beejor
fonte
11
Existem muitos erros na sua resposta, incluindo, entre outros: Nenhum dos seus sabores "modernos" exige -ou ]deve ser escapado fora das classes de personagens. POSIX (BRE / ERE) não possui um caractere de escape nas classes de caracteres. O sabor do regex no RTL do Delphi é realmente baseado no PCRE. Python, Ruby e XML têm seus próprios sabores que estão mais próximos do PCRE do que dos sabores POSIX.
Jan Goyvaerts 23/02
11
@JanGoyvaerts Obrigado pela correção. Os sabores que você mencionou estão realmente mais próximos do PCRE. Quanto às fugas, eu as mantive assim por simplicidade; é mais fácil lembrar apenas para escapar de qualquer lugar do que algumas exceções. Os usuários avançados saberão o que se passa, se quiserem evitar algumas barras invertidas. De qualquer forma, atualizei minha resposta com alguns esclarecimentos que esperamos abordar algumas dessas coisas.
precisa saber é o seguinte
22

Infelizmente, não existe realmente um conjunto de códigos de escape, pois isso varia de acordo com o idioma que você está usando.

No entanto, manter uma página como a Página de Ferramentas de Expressão Regular ou esta Folha de dicas sobre expressões regulares pode ajudar bastante a filtrar rapidamente as coisas.

Dillie-O
fonte
11
A folha de dicas do Addedbytes é muito simplificada e apresenta alguns erros gritantes. Por exemplo, ele diz \<e \>são limites de palavras, o que é verdadeiro apenas (AFAIK) na biblioteca de expressões regulares Boost. Mas em outro lugar ele diz <e >são metacaracteres e deve ser escapado (com \<e \>) para corresponder-los literalmente, o que não é verdade em qualquer sabor
Alan Moore
5

Infelizmente, o significado de coisas como (e \ (são trocados entre as expressões regulares do estilo Emacs e a maioria dos outros estilos). Portanto, se você tentar escapar deles, poderá estar fazendo o oposto do que deseja.

Então você realmente precisa saber qual estilo você está tentando citar.

Darron
fonte
5

O POSIX reconhece várias variações em expressões regulares - expressões regulares básicas (BRE) e expressões regulares estendidas (ERE). E mesmo assim, existem peculiaridades por causa das implementações históricas dos utilitários padronizados pelo POSIX.

Não existe uma regra simples para quando usar qual notação, ou mesmo qual notação um determinado comando usa.

Confira o livro Master Expressões Regulares de Jeff Friedl .

Jonathan Leffler
fonte
4

Realmente não existe. existem cerca de meio zilhão de diferentes sintaxes de expressões regulares; eles parecem se resumir a Perl, EMACS / GNU e AT&T em geral, mas estou sempre ficando surpreso também.

Charlie Martin
fonte
4

Às vezes, o escape simples não é possível com os caracteres que você listou. Por exemplo, o uso de uma barra invertida para escapar de um suporte não funcionará no lado esquerdo de uma string de substituição no sed, a saber

sed -e 's/foo\(bar/something_else/'

Como costumo usar apenas uma definição simples de classe de caractere, a expressão acima se torna

sed -e 's/foo[(]bar/something_else/'

que eu acho que funciona para a maioria das implementações de expressões regulares.

As classes de caracteres BTW são componentes de regexp de baunilha, portanto, eles tendem a funcionar na maioria das situações em que você precisa de caracteres de escape nos regexps.

Edit: Após o comentário abaixo, pensei em mencionar o fato de que você também deve considerar a diferença entre autômatos de estados finitos e autômatos de estados não-finitos ao analisar o comportamento da avaliação regexp.

Você pode consultar o "livro brilhante", também conhecido como Effective Perl ( link higienizado da Amazon ), especificamente o capítulo sobre expressões regulares, para ter uma idéia da diferença nos tipos de avaliação do mecanismo de expressão regular.

Nem todo o mundo é um PCRE!

De qualquer forma, as expressões regulares são tão desajeitadas em comparação com o SNOBOL ! Agora esse foi um curso de programação interessante! Junto com o de Simula .

Ah, as alegrias de estudar na UNSW no final dos anos 70! (-:

Rob Wells
fonte
'sed' é um comando para o qual simples '(' não é especial, mas '\ (' é especial; em contrapartida, PCRE inverte o sentido, então '(' é especial, mas '\ (' não é. o OP está perguntando sobre
Jonathan Leffler
sed é um utilitário * nix que usa um dos conjuntos mais primitivos de avaliação regexp. O PCRE não entra na situação que eu descrevo, pois envolve uma classe diferente de autômatos (in) finitos com a maneira como avalia regexps. Acho que minha sugestão para o conjunto mínimo de sintaxe regexp ainda é válida.
Rob Wells
11
Em um sistema compatível com POSIX, o sed usa o POSIX BRE, que abordo na minha resposta. A versão GNU no sistema Linux moderno usa POSIX BRE com algumas extensões.
Jan Goyvaerts
2

Para o PHP, "é sempre seguro preceder um não alfanumérico com" \ "para especificar que ele representa". - http://php.net/manual/en/regexp.reference.escape.php .

Exceto se for um "ou '.: /

Para escapar de variáveis ​​de padrão de expressão regular (ou variáveis ​​parciais) no PHP, use preg_quote ()

zylstra
fonte
2

Para saber quando e o que escapar sem tentativas é necessário entender com precisão a cadeia de contextos pela qual a cadeia passa. Você especificará a string do lado mais distante ao seu destino final, que é a memória manipulada pelo código de análise regexp.

Esteja ciente de como a cadeia de caracteres na memória é processada: se pode ser uma cadeia simples dentro do código ou uma cadeia inserida na linha de comando, mas a pode ser uma linha de comando interativa ou uma linha de comando declarada dentro de um arquivo de script de shell ou dentro de uma variável na memória mencionada pelo código, ou um argumento (string) por meio de avaliação adicional, ou uma string contendo código gerado dinamicamente com qualquer tipo de encapsulamento ...

Cada um desse contexto atribuiu alguns caracteres com funcionalidade especial.

Quando você deseja passar o caractere literalmente sem usar sua função especial (local para o contexto), esse é o caso em que você precisa escapá-lo, para o próximo contexto ... que pode precisar de outros caracteres de escape que adicionalmente precisam ser escapou no (s) contexto (s) anterior (es). Além disso, pode haver coisas como codificação de caracteres (o mais insidioso é utf-8, porque se parece com ASCII para caracteres comuns, mas pode ser opcionalmente interpretado mesmo pelo terminal, dependendo de suas configurações, para que possa se comportar de maneira diferente, e então pelo atributo de codificação HTML. / XML, é necessário entender o processo com precisão.

Por exemplo, uma regexp na linha de comando começando com perl -npe , precisa ser transferido para um conjunto de chamadas do sistema exec conectando como canal que o arquivo manipula, cada uma dessas chamadas do sistema exec apenas possui uma lista de argumentos que foram separados por espaços (sem escape), e possivelmente pipes (|) e redirecionamento (> N> N> & M), parênteses, expansão interativa *e? ,$(())... (tudo isso são caracteres especiais usados ​​pelo * sh que podem parecer interferir no caractere da expressão regular no próximo contexto, mas são avaliados em ordem: antes da linha de comando. A linha de comando é lida por um programa como bash / sh / csh / tcsh / zsh, essencialmente dentro de aspas duplas ou aspas simples, o escape é mais simples, mas não é necessário citar uma string na linha de comando, porque na maioria das vezes o espaço deve ser prefixado com barra invertida e as aspas são não é necessário deixar disponível a funcionalidade de expansão para os caracteres * e?, mas isso é analisado em contextos diferentes das citadas.Então, quando a linha de comando é avaliada, o regexp obtido na memória (não gravado na linha de comando) recebe o mesmo tratamento que estaria em um arquivo de origem.Para regexp, existe um contexto de conjunto de caracteres entre colchetes [],A expressão regular perl pode ser citada por um grande conjunto de caracteres não alfanuméricos (por exemplo, m // ou m: / better / for / path: ...).

Você tem mais detalhes sobre caracteres em outra resposta, que são muito específicos para o contexto final da expressão regular. Como observei, você mencionou que encontra o escape da regexp com tentativas, provavelmente porque o contexto diferente tem um conjunto de caracteres diferente que confunde sua memória de tentativas (geralmente barra invertida é o caractere usado nesse contexto diferente para escapar de um caractere literal em vez de sua função )

Marco Munari
fonte
0

Para Ionic (Texto Dactilografado), é necessário dobrar a barra para escapar dos caracteres. Por exemplo (isso corresponde a alguns caracteres especiais):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Preste atenção a esses ] [ - _ . /personagens. Eles precisam ser cortados duas vezes. Se você não fizer isso, terá um erro de tipo no seu código.

Alejandro del Río
fonte