Lista de todos os caracteres especiais que precisam ser escapados em uma regex

108

Estou tentando criar um aplicativo que corresponda a um modelo de mensagem com uma mensagem que um usuário está tentando enviar. Estou usando Java regex para corresponder à mensagem. O modelo / mensagem pode conter caracteres especiais.

Como obteria a lista completa de caracteres especiais que precisam ser escapados para que minha regex funcione e corresponda no máximo de casos possíveis?

Existe uma solução universal para escapar de todos os caracteres especiais no Java regex?

Avinash Nair
fonte

Respostas:

94

Você pode olhar o javadoc da classe Pattern: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

Você precisa escapar de qualquer caractere listado lá se quiser o caractere regular e não o significado especial.

Como uma solução talvez mais simples, você pode colocar o modelo entre \ Q e \ E - tudo entre eles é considerado como escape.

Sorin
fonte
43
Se você achar que \ Q e \ E são difíceis de lembrar, você pode usar Pattern.quote ("...")
mkdev
19
Gostaria que você realmente os tivesse declarado
Aleksandr Dubinsky
Por que, @AleksandrDubinsky?
Sorin
55
@Sorin Porque é o espírito (não, política?) Do Stack Exchange declarar a resposta em sua resposta, em vez de apenas vincular a um recurso externo. Além disso, essa página também não tem uma lista clara. Uma lista pode ser encontrada aqui: docs.oracle.com/javase/tutorial/essential/regex/literals.html , mas afirma "Em certas situações, os caracteres especiais listados acima não serão tratados como metacaracteres," sem explicar o que acontecerá se alguém tenta escapar deles. Em suma, essa pergunta merece uma boa resposta.
Aleksandr Dubinsky
8
"tudo entre eles [ \Qe \E] é considerado como escapado" - exceto outros \Q'se \E' (que podem ocorrer potencialmente dentro do regex original). Então, é melhor usar Pattern.quotecomo sugerido aqui e não reinventar a roda.
Sasha
92
  • Os caracteres Java que devem ser escapados em expressões regulares são:
    \.[]{}()<>*+-=!?^$|
  • Dois dos colchetes de fechamento ( ]e }) só precisam ser escapados após a abertura do mesmo tipo de colchete.
  • Entre []colchetes, alguns caracteres (como +e -) às vezes funcionam sem escape.
Tobi G.
fonte
Existe alguma maneira de não escapar, mas permitir esses personagens?
Dominika
1
Escapar de um caractere significa permitir o caractere em vez de interpretá-lo como um operador.
Tobi G.
4
Nem sempre o escape -em []pode funcionar, pois é usado para definir intervalos. É mais seguro escapar disso. Por exemplo, os padrões [-]e [-)]correspondem à string, -mas não com [(-)].
Kenston Choi
1
Embora a resposta aceita responda à pergunta, essa resposta foi mais útil para mim quando eu estava apenas procurando por uma lista rápida.
Old Nick
-=!não precisa necessariamente de escape, depende do contexto. Por exemplo, como uma única letra, eles funcionam como um regex constante.
Hawk
29

Para escapar, você pode apenas usar isso do Java 1.5 :

Pattern.quote("$test");

Você vai corresponder exatamente à palavra $test

madx
fonte
Por que esta não é a resposta mais bem avaliada? Ele resolve o problema sem entrar nos detalhes complexos de listar todos os caracteres que precisam de escape e é parte do JDK - sem necessidade de escrever nenhum código extra! Simples!
Volksman
17

De acordo com a página de documentação de Literais de String / Metacaracteres , eles são:

<([{\^-=$!|]})?*+.>

Também seria legal ter essa lista referenciada em algum lugar no código, mas não sei onde isso poderia estar ...

Bohdan
fonte
11
String escaped = tnk.replaceAll("[\\<\\(\\[\\{\\\\\\^\\-\\=\\$\\!\\|\\]\\}\\)\\?\\*\\+\\.\\>]", "\\\\$0");
marbel82 de
1
O javadoc de padrão diz que é um erro usar uma barra invertida antes de qualquer caractere alfabético que não denota uma construção com escape, mas uma barra invertida pode ser usada antes de um caractere não alfabético, independentemente de esse caractere ser parte de uma construção sem escape. Portanto, um regex muito mais simples será suficiente: s.replaceAll("[\\W]", "\\\\$0")onde \Wdesigna caracteres não-word.
Joe Bowbeer
6

Combinando o que todos disseram, proponho o seguinte, para manter a lista de caracteres especiais para RegExp claramente listados em sua própria String e para evitar ter que tentar analisar visualmente milhares de "\\" 's. Isso parece funcionar muito bem para mim:

final String regExSpecialChars = "<([{\\^-=$!|]})?*+.>";
final String regExSpecialCharsRE = regExSpecialChars.replaceAll( ".", "\\\\$0");
final Pattern reCharsREP = Pattern.compile( "[" + regExSpecialCharsRE + "]");

String quoteRegExSpecialChars( String s)
{
    Matcher m = reCharsREP.matcher( s);
    return m.replaceAll( "\\\\$0");
}
NeuroDuck
fonte
5

Na sugestão de @Sorin dos documentos do Java Pattern, parece que os caracteres para escapar são pelo menos:

\.[{(*+?^$|
pete
fonte
4
String escaped = regexString.replaceAll("([\\\\\\.\\[\\{\\(\\*\\+\\?\\^\\$\\|])", "\\\\$1");
fracz
2
)também deve ser escapado, e dependendo se você está dentro ou fora de uma classe de caractere, pode haver mais caracteres para escapar, caso em que Pattern.quotefaz um bom trabalho em escapar uma string para uso dentro e fora da classe de caractere.
nhahtdh
3

O Pattern.quote(String s)tipo de faz o que você quer. No entanto, deixa um pouco a desejar; na verdade não escapa os caracteres individuais, apenas envolve a string com \Q...\E.

Não existe um método que faça exatamente o que você está procurando, mas a boa notícia é que é bastante simples escapar de todos os caracteres especiais em uma expressão regular Java:

regex.replaceAll("[\\W]", "\\\\$0")

Por que isso funciona? Bem, a documentação para Patterndiz especificamente que é permitido escapar caracteres não alfabéticos que não necessariamente precisam ser escapados:

É um erro usar uma barra invertida antes de qualquer caractere alfabético que não denota uma construção de escape; eles são reservados para futuras extensões da linguagem de expressão regular. Uma barra invertida pode ser usada antes de um caractere não alfabético, independentemente de esse caractere ser parte de uma construção sem escape.

Por exemplo, ;não é um caractere especial em uma expressão regular. No entanto, se você escapar, Patternainda interpretará \;como ;. Aqui estão mais alguns exemplos:

  • >torna-se o \>que é equivalente a>
  • [torna-se o \[que é a forma escapada de[
  • 8está parado 8.
  • \)torna-se \\\)qual é as formas escapadas \e (concatenadas.

Observação: a chave é a definição de "não alfabético", que na documentação realmente significa caracteres "não palavra " ou caracteres fora do conjunto de caracteres[a-zA-Z_0-9] .

veículo com rodas
fonte
2

do outro lado da moeda, você deve usar regex "não-char" que se pareça com este se caracteres especiais = allChars - número - ABC - espaço no contexto do seu aplicativo.

String regepx = "[^\\s\\w]*";
Bo6Bear
fonte
2

embora a resposta seja para Java, mas o código pode ser facilmente adaptado a partir desta extensão Kotlin String que criei (adaptado daquele @brcolow fornecido):

private val escapeChars = charArrayOf(
    '<',
    '(',
    '[',
    '{',
    '\\',
    '^',
    '-',
    '=',
    '$',
    '!',
    '|',
    ']',
    '}',
    ')',
    '?',
    '*',
    '+',
    '.',
    '>'
)

fun String.escapePattern(): String {
    return this.fold("") {
      acc, chr ->
        acc + if (escapeChars.contains(chr)) "\\$chr" else "$chr"
    }
}

fun main() {
    println("(.*)".escapePattern())
}

estampas \(\.\*\)

verifique-o em ação aqui https://pl.kotl.in/h-3mXZkNE

pocesar
fonte
1

Supondo que você tenha e confie (para ser autoritário) a lista de caracteres de escape que a regex Java usa (seria bom se esses caracteres fossem expostos em algum membro da classe Pattern), você pode usar o seguinte método para escapar o caractere se for realmente necessário:

private static final char[] escapeChars = { '<', '(', '[', '{', '\\', '^', '-', '=', '$', '!', '|', ']', '}', ')', '?', '*', '+', '.', '>' };

private static String regexEscape(char character) {
    for (char escapeChar : escapeChars) {
        if (character == escapeChar) {
            return "\\" + character;
        }
    }
    return String.valueOf(character);
}
sobrancelha
fonte