TLDR: use em theString = theString.replace("\\", "\\\\");
vez disso.
Problema
replaceAll(target, replacement)
usa sintaxe de expressão regular (regex) para target
e parcialmente para replacement
.
O problema é que \
é um caractere especial em regex (pode ser usado como \d
para representar dígito) e em literal de String (pode ser usado como "\n"
para representar separador de linha ou \"
para escapar do símbolo de aspas duplas que normalmente representaria o fim da literal de string).
Em ambos os casos, para criar um \
símbolo, podemos escapá- lo (torná-lo literal em vez de um caractere especial) colocando mais \
antes dele (como escapamos "
em literais de strings via \"
).
Portanto, a target
expressão regular que representa o \
símbolo precisará ser mantida \\
, e a string literal que representa esse texto precisará se parecer "\\\\"
.
Então, escapamos \
duas vezes:
- uma vez na regex
\\
- uma vez no literal String
"\\\\"
(cada um \
é representado como "\\"
).
No caso de replacement
\
também é especial lá. Ele nos permite escapar de outro caractere especial $
que, por meio de $x
notação, nos permite usar parte dos dados correspondidos por regex e mantidos capturando o grupo indexado x
, como, por exemplo , "012".replaceAll("(\\d)", "$1$1")
irá corresponder a cada dígito, colocá-lo no grupo de captura 1 e $1$1
substituí-lo por suas duas cópias (duplicará) resultando em "001122"
.
Então, novamente, para deixar replacement
representar \
literal, precisamos escapar dela com mais, o \
que significa que:
- a substituição deve conter dois caracteres de barra invertida
\\
- e String literal que representa
\\
parece"\\\\"
MAS, como queremos replacement
manter duas barras invertidas, precisaremos "\\\\\\\\"
(cada uma \
representada por uma "\\\\"
).
Então, a versão com replaceAll
pode parecer
replaceAll("\\\\", "\\\\\\\\");
Maneira mais fácil
Para tornar a vida mais fácil Java fornece ferramentas para escapar automaticamente texto target
e replacement
partes. Portanto, agora podemos focar apenas em strings e esquecer a sintaxe regex:
replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))
que no nosso caso pode parecer
replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))
Melhor ainda
Se realmente não precisamos de suporte à sintaxe regex, não vamos envolver replaceAll
nada. Em vez disso, vamos usar replace
. Ambos os métodos substituirão todos os target
s, mas replace
não envolvem sintaxe regex. Então você poderia simplesmente escrever
theString = theString.replace("\\", "\\\\");