String.replace Tutti i singoli backslash con doppi backslash


122

Sto cercando di convertire il file String \something\in String \\something\\uso replaceAll, ma continuo a ricevere tutti i tipi di errori. Ho pensato che questa fosse la soluzione:

theString.replaceAll("\\", "\\\\");

Ma questo dà la seguente eccezione:

java.util.regex.PatternSyntaxException: Unexpected internal error near index 1

Risposte:


204

L' String#replaceAll()interpreta l'argomento come un'espressione regolare . Il \è un carattere di escape in entrambi String e regex. Devi eseguire un doppio escape per regex:

string.replaceAll("\\\\", "\\\\\\\\");

Ma non hai necessariamente bisogno di regex per questo, semplicemente perché vuoi una sostituzione esatta carattere per carattere e non hai bisogno di schemi qui. Quindi String#replace()dovrebbe essere sufficiente:

string.replace("\\", "\\\\");

Aggiornamento : secondo i commenti, sembra che tu voglia utilizzare la stringa nel contesto JavaScript. Forse faresti meglio a usare StringEscapeUtils#escapeEcmaScript()invece per coprire più personaggi.


In realtà, viene utilizzato in un AST JavaScript che dovrebbe essere riconvertito in sorgente. La tua soluzione funziona. Grazie!
Frank Groeneveld,

2
Se vuoi usarlo String#replaceAll()comunque, puoi citare la stringa sostitutiva con Matcher # quoteReplacement () :theString.replaceAll("\\", Matcher.quoteReplacement("\\\\"));
phse

Matcher.quoteReplacement (...) è un buon modo! Si prega di vedere la risposta di Pshemo!
Hartmut P.

14

Per evitare questo tipo di problemi, puoi usare replace(che accetta una stringa semplice) invece di replaceAll(che accetta un'espressione regolare). Avrai ancora bisogno di sfuggire ai backslash, ma non nei modi selvaggi richiesti con le espressioni regolari.


10

TLDR: usa theString = theString.replace("\\", "\\\\");invece.


Problema

replaceAll(target, replacement)usa la sintassi delle espressioni regolari (regex) per targete parzialmente per replacement.

Il problema è che \è un carattere speciale in regex (può essere usato come \dper rappresentare una cifra) e in String literal (può essere usato come "\n"per rappresentare il separatore di riga o \"per sfuggire al simbolo di virgolette doppie che normalmente rappresenterebbe la fine della stringa letterale).

In entrambi questi casi, per creare un \simbolo possiamo sfuggirgli (renderlo letterale invece di un carattere speciale) inserendo ulteriori \prima di esso (come se "usassimo l' escape in stringhe letterali tramite \").

Quindi per targetregex che rappresenta il \simbolo sarà necessario tenere \\e la stringa letterale che rappresenta tale testo dovrà essere simile "\\\\".

Quindi siamo fuggiti \due volte:

  • una volta in regex \\
  • una volta in String literal "\\\\"(ognuno \è rappresentato come "\\").

In caso di replacement \è anche speciale lì. Ci permette di sfuggire ad altri caratteri speciali $che, tramite $xnotazione, ci permette di usare parte di dati abbinati da regex e trattenuti catturando il gruppo indicizzato come x, come "012".replaceAll("(\\d)", "$1$1")corrisponderà ad ogni cifra, lo $1$1metterà nel gruppo di cattura 1 e lo sostituirà con le sue due copie (lo duplicherà) risultando in "001122".

Quindi, di nuovo, per far replacementrappresentare il \letterale dobbiamo evitarlo con addizionale \che significa che:

  • la sostituzione deve contenere due caratteri backslash \\
  • e String letterale che rappresenta \\assomiglia a"\\\\"

MA poiché vogliamo replacementmantenere due backslash avremo bisogno "\\\\\\\\"(ciascuno \rappresentato da uno "\\\\").

Quindi la versione con replaceAllpuò assomigliare

replaceAll("\\\\", "\\\\\\\\");

Modo più semplice

Per rendere la vita più facile, Java fornisce strumenti per eseguire automaticamente l'escape di testo targete replacementparti. Quindi ora possiamo concentrarci solo sulle stringhe e dimenticare la sintassi delle espressioni regolari:

replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))

che nel nostro caso può assomigliare

replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))

Anche meglio

Se non abbiamo davvero bisogno del supporto della sintassi regex, non coinvolgiamo replaceAllaffatto. Invece usiamo replace. Entrambi i metodi sostituiranno tutti target i messaggi, ma replacenon implicano la sintassi delle espressioni regolari. Quindi potresti semplicemente scrivere

theString = theString.replace("\\", "\\\\");

7

Dovrai eseguire l'escape della barra rovesciata (con escape) nel primo argomento in quanto è un'espressione regolare. Anche la sostituzione (secondo argomento - vedi Matcher # replaceAll (String) ) ha il suo significato speciale di barre rovesciate, quindi dovrai sostituirle con:

theString.replaceAll("\\\\", "\\\\\\\\");

3

Sì ... quando il compilatore di espressioni regolari vede il pattern che gli hai dato, vede solo una singola barra rovesciata (poiché il lexer di Java ha trasformato il doppio backwhack in uno singolo). Devi sostituire "\\\\"con "\\\\", che tu ci creda o no! Java ha davvero bisogno di una buona sintassi delle stringhe non elaborate.

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.