String.replaceВсе одиночная обратная косая черта с двойной обратной косой чертой
Я пытаюсь преобразовать String
\something\
в String
\\something\\
с помощью replaceAll
, но я все время получаю всевозможные ошибки. Я думал, что это решение:
theString.replaceAll("\\", "\\\\");
Но это дает следующее исключение:
java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
Ответы
Ответ 1
String#replaceAll()
интерпретирует этот аргумент как регулярное выражение. \
является escape-символом в как String
, так и regex
. Вам нужно дважды уйти от него для регулярного выражения:
string.replaceAll("\\\\", "\\\\\\\\");
Но для этого вам не обязательно нужно регулярное выражение, просто потому, что вам нужна точная замена по каждому символу, и вам здесь не нужны шаблоны. Поэтому String#replace()
должно быть достаточно:
string.replace("\\", "\\\\");
Обновить: в соответствии с комментариями вы, похоже, хотите использовать строку в контексте JavaScript. Возможно, вам лучше использовать StringEscapeUtils#escapeEcmaScript()
, чтобы покрыть больше символов.
Ответ 2
Чтобы избежать подобных проблем, вы можете использовать replace
(который принимает простую строку) вместо replaceAll
(который принимает регулярное выражение). Вам все равно придется скрывать обратную косую черту, но не в диких направлениях, требуемых регулярными выражениями.
Ответ 3
TL;DR: используйте theString = theString.replace("\\", "\\\\");
вместо.
проблема
replaceAll(target, replacement)
использует синтаксис регулярного выражения (regex) для target
и частично для replacement
.
Проблема заключается в том, что \
является специальным символом в регулярном выражении (его можно использовать как \d
для представления цифры) и в строковом литерале (его можно использовать как "\n"
для представления разделителя строк или \"
чтобы избежать символа двойной кавычки, который обычно представляют конец строкового литерала).
В обоих случаях для создания символа \
мы можем его избежать (сделаем его буквальным вместо специального символа), добавив дополнительные \
перед ним (например, мы убежим "
в строковых литералах через \"
).
Поэтому для target
регулярного выражения, представляющего символ \
, нужно будет удерживать \\
, а строковый литерал, представляющий такой текст, должен выглядеть так: "\\\\"
.
Таким образом, мы избежали \
дважды:
- один раз в regex
\\
- один раз в
"\\\\"
(каждый \
представлен как "\\"
).
В случае replacement
\
также является специальным. Это позволяет нам избежать другого специального символа $
который через нотацию $x
позволяет нам использовать часть данных, сопоставляемую регулярным выражением, и удерживаться захватом группы, проиндексированной как x
, например "012".replaceAll("(\\d)", "$1$1")
будет соответствовать каждой цифре, поместить ее в группу 1 и $1$1
заменит ее двумя копиями (она будет дублировать ее), что приведет к "001122"
.
Итак, снова, чтобы replacement
представляла \
literal, нам нужно избежать ее с помощью дополнительного \
что означает:
- замена должна содержать два символа обратной косой черты
\\
- и строковый литерал, который представляет
\\
выглядит как "\\\\"
НО, так как мы хотим, чтобы replacement
удерживала две обратные "\\\\\\\\"
черты, нам понадобится "\\\\\\\\"
(каждый \
представлен одним "\\\\"
).
Так что версия с replaceAll
может выглядеть так:
replaceAll("\\\\", "\\\\\\\\");
Простой способ
Чтобы упростить жизнь, Java предоставляет инструменты для автоматического удаления текста в target
и replacement
части. Итак, теперь мы можем сосредоточиться только на строках и забыть о синтаксисе regex:
replaceAll(Pattern.quote(target), Matcher.quoteReplacement(replacement))
который в нашем случае может выглядеть
replaceAll(Pattern.quote("\\"), Matcher.quoteReplacement("\\\\"))
Даже лучше
Если нам не нужна поддержка синтаксиса regex, вы можете вообще не включать replaceAll
. Вместо этого используйте replace
. Оба метода заменят все target
s, но replace
не включает синтаксис regex. Так что вы могли бы просто написать
theString = theString.replace("\\", "\\\\");
Ответ 4
Вам нужно будет избежать обратного слэша (экранированного) в первом аргументе, поскольку это регулярное выражение. Замена (второй аргумент - см. Matcher # replaceAll (String)) также имеет особое значение обратных косых черт, поэтому вам придется заменить их на:
theString.replaceAll("\\\\", "\\\\\\\\");
Ответ 5
Да... к тому времени, когда компилятор regex увидит шаблон, который вы ему дали, он видит только одну обратную косую черту (поскольку Java lexer превратил двойной backwhack в один). Вам нужно заменить "\\\\"
на "\\\\"
, верьте или нет! Java действительно нуждается в хорошем синтаксисе строки.