Elenco di tutti i caratteri speciali che devono essere sottoposti a escape in una regex


108

Sto cercando di creare un'applicazione che corrisponda a un modello di messaggio con un messaggio che un utente sta tentando di inviare. Sto usando Java regex per abbinare il messaggio. Il modello / messaggio può contenere caratteri speciali.

Come posso ottenere l'elenco completo dei caratteri speciali di cui è necessario eseguire l'escape affinché la mia regex funzioni e corrisponda nel massimo dei casi possibili?

Esiste una soluzione universale per l'escape di tutti i caratteri speciali nella regex Java?

Risposte:


94

Puoi guardare il javadoc della classe Pattern: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

È necessario eseguire l'escape di qualsiasi carattere elencato lì se si desidera il carattere normale e non il significato speciale.

Come soluzione forse più semplice, puoi mettere il modello tra \ Q e \ E - tutto ciò che si trova tra di loro è considerato come sfuggito.


43
Se trovi \ Q e \ E difficili da ricordare puoi usare invece Pattern.quote ("...")
mkdev

19
Vorrei che li avessi effettivamente dichiarati
Aleksandr Dubinsky il

Perché, @AleksandrDubinsky?
Sorin

55
@ Sorin Perché è lo spirito (anzi, la politica?) Di Stack Exchange affermare la risposta nella tua risposta piuttosto che collegarti a una risorsa fuori sede. Inoltre, anche quella pagina non ha un elenco chiaro. Un elenco può essere trovato qui: docs.oracle.com/javase/tutorial/essential/regex/literals.html , ma afferma "In alcune situazioni i caratteri speciali elencati sopra non saranno trattati come metacaratteri", senza spiegare cosa succederà se si cerca di sfuggirgli. Insomma, questa domanda merita una buona risposta.
Aleksandr Dubinsky

8
"tutto ciò che è compreso tra loro [ \Qe \E] è considerato come sfuggito" - eccetto gli altri \Qe \E(che potenzialmente possono verificarsi all'interno dell'espressione regolare originale). Quindi, è meglio usare Pattern.quotecome suggerito qui e non reinventare la ruota.
Sasha

92
  • I caratteri Java che devono essere sottoposti a escape nelle espressioni regolari sono:
    \.[]{}()<>*+-=!?^$|
  • È necessario eseguire l'escape di due delle parentesi di chiusura ( ]e }) solo dopo aver aperto lo stesso tipo di parentesi.
  • Tra []parentesi graffe alcuni caratteri (come +e -) a volte funzionano senza escape.

C'è un modo per non scappare ma consentire a quei personaggi?
Dominika

1
Sfuggire a un carattere significa consentire al personaggio invece di interpretarlo come un operatore.
Tobi G.

4
Senza caratteri -di escape all'interno []potrebbe non funzionare sempre poiché viene utilizzato per definire gli intervalli. È più sicuro sfuggirgli. Ad esempio, i modelli [-]e [-)]corrispondono alla stringa -ma non con [(-)].
Kenston Choi

1
Anche se la risposta accettata risponde alla domanda, questa risposta è stata più utile per me quando stavo solo cercando un elenco rapido.
Old Nick il

-=!non è necessariamente necessario eseguire l'escape, dipende dal contesto. Ad esempio come una singola lettera funzionano come una regex costante.
Hawk

29

Per scappare potresti semplicemente usare questo da Java 1.5 :

Pattern.quote("$test");

Abbinerai esattamente la parola $test


Perché questa non è la risposta più apprezzata? Risolve il problema senza entrare nei dettagli complessi dell'elenco di tutti i caratteri che devono essere sfuggiti e fa parte del JDK - non è necessario scrivere alcun codice aggiuntivo! Semplice!
Volksman

17

Secondo la pagina di documentazione String Literals / Metacharacters , sono:

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

Inoltre sarebbe bello avere quella lista da qualche parte nel codice, ma non so dove potrebbe essere ...


11
String escaped = tnk.replaceAll("[\\<\\(\\[\\{\\\\\\^\\-\\=\\$\\!\\|\\]\\}\\)\\?\\*\\+\\.\\>]", "\\\\$0");
marbel82

1
Il javadoc Pattern dice che è un errore usare una barra rovesciata prima di qualsiasi carattere alfabetico che non denota un costrutto con escape, ma una barra rovesciata può essere utilizzata prima di un carattere non alfabetico indipendentemente dal fatto che quel carattere faccia parte di un costrutto senza escape. Quindi una regex molto più semplice sarà sufficiente: s.replaceAll("[\\W]", "\\\\$0")dove \Wdesigna caratteri non di parole.
Joe Bowbeer

6

Combinando ciò che tutti hanno detto, propongo quanto segue, per mantenere l'elenco dei caratteri speciali per RegExp chiaramente elencato nella propria stringa e per evitare di dover cercare di analizzare visivamente migliaia di "\\". Questo sembra funzionare abbastanza bene per me:

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");
}

5

Su suggerimento di @ Sorin dei documenti di Java Pattern, sembra che i caratteri per sfuggire siano almeno:

\.[{(*+?^$|

4
String escaped = regexString.replaceAll("([\\\\\\.\\[\\{\\(\\*\\+\\?\\^\\$\\|])", "\\\\$1");
fracz

2
)deve anche essere sottoposto a escape e, a seconda che tu sia all'interno o all'esterno di una classe di caratteri, possono esserci più caratteri di cui eseguire l'escape, nel qual caso Pattern.quotefa un buon lavoro nell'escape di una stringa da utilizzare sia all'interno che all'esterno della classe di caratteri.
nhahtdh

3

Il Pattern.quote(String s) tipo di fa quello che vuoi. Tuttavia lascia un po 'a desiderare; in realtà non esegue l'escape dei singoli caratteri, si limita a avvolgere la stringa con \Q...\E.

Non esiste un metodo che faccia esattamente quello che stai cercando, ma la buona notizia è che in realtà è abbastanza semplice sfuggire a tutti i caratteri speciali in un'espressione regolare Java:

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

Perché funziona? Bene, la documentazione per Patternspecifica dice che è consentito eseguire l'escape di caratteri non alfabetici che non devono necessariamente essere sottoposti a escape:

È un errore utilizzare una barra rovesciata prima di qualsiasi carattere alfabetico che non denota un costrutto con escape; questi sono riservati per future estensioni al linguaggio delle espressioni regolari. È possibile utilizzare una barra rovesciata prima di un carattere non alfabetico indipendentemente dal fatto che quel carattere faccia parte di un costrutto senza caratteri di escape.

Ad esempio, ;non è un carattere speciale in un'espressione regolare. Tuttavia, se esegui l'escape, Patternverrà comunque interpretato \;come ;. Ecco alcuni altri esempi:

  • >diventa \>che è equivalente a>
  • [diventa \[che è la forma sfuggita di[
  • 8è ancora 8.
  • \)diventa \\\)che è le forme sfuggite \e (concatenate.

Nota: la chiave è la definizione di "non alfabetico", che nella documentazione significa in realtà caratteri "non parole " o caratteri al di fuori del set di caratteri [a-zA-Z_0-9].


2

sull'altro lato della medaglia, dovresti usare regex "non-char" che assomiglia a questo se caratteri speciali = allChars - numero - ABC - spazio nel contesto della tua app.

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

2

sebbene la risposta sia per Java, ma il codice può essere facilmente adattato da questa estensione Kotlin String che ho inventato (adattata da quella fornita da @brcolow):

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())
}

stampe \(\.\*\)

controllalo in azione qui https://pl.kotl.in/h-3mXZkNE


1

Supponendo che tu abbia e ti fidi (per essere autorevole) dell'elenco dei caratteri di escape che Java utilizza (sarebbe carino se questi caratteri fossero esposti in qualche membro della classe Pattern) puoi usare il seguente metodo per eseguire l'escape del carattere se è effettivamente necessario:

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

private static String regexEscape(char character) {
    for (char escapeChar : escapeChars) {
        if (character == escapeChar) {
            return "\\" + character;
        }
    }
    return String.valueOf(character);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.