TLDR: utilizar theString = theString.replace("\\", "\\\\");
en su lugar.
Problema
replaceAll(target, replacement)
usa sintaxis de expresión regular (regex) para target
y parcialmente para replacement
.
El problema es que \
es un carácter especial en regex (se puede usar como \d
para representar un dígito) y en String literal (se puede usar "\n"
para representar un separador de línea o \"
para escapar del símbolo de comillas dobles que normalmente representaría el final del literal de cadena).
En ambos casos, para crear un \
símbolo, podemos escapar de él (hacerlo literal en lugar de caracteres especiales) colocando adicional \
antes (como escapamos "
en literales de cadena a través de \"
).
Por lo tanto, para target
regexar el \
símbolo que representa tendrá que mantenerse \\
, y el literal de cadena que representa dicho texto deberá parecerse "\\\\"
.
Entonces escapamos \
dos veces:
- una vez en regex
\\
- una vez en cadena literal
"\\\\"
(cada uno \
se representa como "\\"
).
En caso de replacement
\
que también sea especial allí. Nos permite escapar de otros caracteres especiales $
que a través de la $x
notación, nos permite usar una parte de los datos que coinciden con expresiones regulares y que se mantienen al capturar el grupo indexado x
, ya que , como "012".replaceAll("(\\d)", "$1$1")
coincidirá con cada dígito, colocarlo en el grupo de captura 1 y $1$1
reemplazarlo con sus dos copias (lo duplicará) resultando en "001122"
.
Entonces, de nuevo, para dejar de replacement
representar \
literal, necesitamos escapar de él con adicional \
que significa que:
- el reemplazo debe contener dos caracteres de barra invertida
\\
- y literal de cadena que representa
\\
parece"\\\\"
PERO ya que queremos replacement
mantener dos barras invertidas necesitaremos "\\\\\\\\"
(cada una \
representada por una "\\\\"
).
Entonces la versión con replaceAll
puede verse como
replaceAll("\\\\", "\\\\\\\\");
Manera más fácil
Para hacer la vida más fácil, Java proporciona herramientas para escapar automáticamente texto target
y replacement
partes. Entonces ahora podemos enfocarnos solo en cadenas y olvidarnos de la sintaxis de expresiones regulares:
replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))
que en nuestro caso puede parecer
replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))
Aun mejor
Si realmente no necesitamos soporte de sintaxis de expresiones regulares, no nos involucremos replaceAll
en absoluto. En cambio, vamos a usar replace
. Ambos métodos reemplazarán todos los target
s, pero replace
no involucran sintaxis de expresiones regulares. Entonces podrías simplemente escribir
theString = theString.replace("\\", "\\\\");