String.Replaceall Backslashes únicas com barragens duplas
-
19-09-2019 - |
Pergunta
Estou tentando converter o String
\something\
no String
\\something\\
usando replaceAll
, mas continuo recebendo todos os tipos de erros. Eu pensei que essa era a solução:
theString.replaceAll("\\", "\\\\");
Mas isso dá a exceção abaixo:
java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
Solução
o String#replaceAll()
interpreta o argumento como um expressão regular. o \
é um personagem de fuga em Ambas String
e regex
. Você precisa dobrar duas vezes para regex:
string.replaceAll("\\\\", "\\\\\\\\");
Mas você não precisa necessariamente Regex para isso, simplesmente porque deseja uma substituição exata de personagem por caractere e não precisa de padrões aqui. Então String#replace()
deve ser suficiente:
string.replace("\\", "\\\\");
Atualizar: De acordo com os comentários, você parece querer usar a string no contexto JavaScript. Talvez seja melhor usar StringEscapeUtils#escapeEcmaScript()
Em vez disso, para cobrir mais personagens.
Outras dicas
Para evitar esse tipo de problema, você pode usar replace
(que leva uma corda simples) em vez de replaceAll
(que leva uma expressão regular). Você ainda precisará escapar de barras -barras, mas não das maneiras selvagens necessárias com expressões regulares.
TLDR: Use theString = theString.replace("\\", "\\\\");
em vez de.
Problema
replaceAll(target, replacement)
usa a sintaxe de expressão regular (regex) para target
e parcialmente para replacement
.
O problema é isso \
é um personagem especial em regex (pode ser usado como \d
para representa o dígito) e em literais de corda (pode ser usado como "\n"
Para representar o separador de linha ou \"
para escapar do símbolo de citação dupla que normalmente representaria o final da string literal).
Em ambos os casos para criar \
Símbolo que podemos escapar (tornar -o literal em vez de caráter especial) colocando \
antes disso (como nós escapamos "
em literais de cordas via \"
).
Então para target
regex representando \
Símbolo precisará segurar \\
, e a literal de cordas que representam esse texto precisarão parecer "\\\\"
.
Então nós escapamos \
duas vezes:
- uma vez em regex
\\
- uma vez em string literal
"\\\\"
(cada\
é representado como"\\"
).
No caso de replacement
\
também é especial lá. Nos permite escapar de outro personagem especial $
Qual via $x
notação, nos permite usar a parte dos dados correspondidos por Regex e mantidos capturando o grupo indexado como x
, Curti "012".replaceAll("(\\d)", "$1$1")
combinará cada dígito, coloque -o na captura do Grupo 1 e $1$1
o substituirá por suas duas cópias (ele duplicará) resultando em "001122"
.
Então, novamente, para deixar replacement
representar \
literal, precisamos escapar disso com adicional \
o que significa que:
- A substituição deve conter dois caracteres de barragem
\\
- e literal de cordas que representa
\\
parece"\\\\"
Mas desde que queremos replacement
segurar dois barras de barriga que precisaremos "\\\\\\\\"
(cada \
representado por um "\\\\"
).
Então versão com replaceAll
pode parecer assim
replaceAll("\\\\", "\\\\\\\\");
Maneira mais fácil
Para entender a vida mais fácil, o Java fornece ferramentas para escapar automaticamente no texto em target
e replacement
peças. Então agora podemos nos concentrar apenas em strings e esquecer a sintaxe regex:
replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))
Qual no nosso caso pode parecer
replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))
Melhor ainda
Se realmente não precisamos de suporte de sintaxe da regex, não envolva replaceAll
de forma alguma. Em vez disso, vamos usar replace
. Ambos os métodos substituirão tudo target
s, mas replace
Não envolve sintaxe regex. Então você pode simplesmente escrever
theString = theString.replace("\\", "\\\\");
Você precisará escapar da barra de barriga (escapada) no primeiro argumento, pois é uma expressão regular. Substituição (2º argumento - ver Matcher#replaceall (string)) também tem seu significado especial de barris, então você terá que substituí -las para:
theString.replaceAll("\\\\", "\\\\\\\\");
Sim ... quando o compilador Regex vê o padrão que você deu, ele vê apenas uma única barra de barra (já que o Lexer de Java transformou o backwhack duplo em um único). Você precisa substituir "\\\\"
com "\\\\"
, Acredite ou não! O Java realmente precisa de uma boa sintaxe de cordas cruas.