Строка.Замените все одиночные обратные косые черты двойными обратными косыми чертами

StackOverflow https://stackoverflow.com/questions/1701839

Вопрос

Я пытаюсь преобразовать String \something\ в String \\something\\ используя replaceAll, но я продолжаю получать всевозможные ошибки.Я думал, что это и есть решение:

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

Но это дает приведенное ниже исключение:

java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
Это было полезно?

Решение

В String#replaceAll() интерпретирует аргумент как регулярное выражение\ является экранирующим символом в и то, и другое String и regex.Вам нужно дважды экранировать его для регулярного выражения:

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

Но вам не обязательно нужно регулярное выражение для этого, просто потому, что вы хотите точную замену посимвольно и вам здесь не нужны шаблоны.Итак String#replace() должно хватить:

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

Обновить:согласно комментариям, вы, похоже, хотите использовать строку в контексте JavaScript.Возможно, вам лучше использовать StringEscapeUtils#escapeEcmaScript() вместо этого, чтобы охватить больше символов.

Другие советы

Чтобы избежать подобного рода неприятностей, вы можете использовать replace (который принимает простую строку) вместо replaceAll (который принимает регулярное выражение).Вам все равно нужно будет избегать обратных косых черт, но не дикими способами, требуемыми при использовании регулярных выражений.

TLDR ( ДВУ ):использование theString = theString.replace("\\", "\\\\"); вместо этого.


Проблема

replaceAll(target, replacement) использует синтаксис регулярного выражения (regex) для target и частично для replacement.

Проблема в том, что \ является специальным символом в регулярном выражении (его можно использовать как \d to представляет цифру) и в строковом литерале (его можно использовать как "\n" для представления разделителя строк или \" чтобы избежать символа двойной кавычки, который обычно представляет конец строкового литерала).

В обоих этих случаях для создания \ символ, который мы можем побег это (сделайте это буквальным вместо специального символа), поместив дополнительные \ перед этим (как будто мы убегаем " в строковых литералах через \").

Так что к target регулярное выражение , представляющее \ символ нужно будет удерживать \\, и строковый литерал , представляющий такой текст , должен будет выглядеть следующим образом "\\\\".

Итак, мы сбежали \ дважды:

  • один раз в регулярном выражении \\
  • один раз в строковом литерале "\\\\" (каждый \ представляется в виде "\\").

В случае replacement \ там тоже есть что-то особенное.Это позволяет нам экранировать другой специальный символ $ который через $x обозначение, позволяет нам использовать часть данных, сопоставляемых регулярным выражением и хранящихся группой захвата, индексированной как x, как "012".replaceAll("(\\d)", "$1$1") будет соответствовать каждой цифре, поместите ее в группу захвата 1 и $1$1 заменит его двумя своими копиями (он будет дублировать его), что приведет к "001122".

Итак, еще раз, чтобы позволить replacement представлять \ буквально нам нужно избежать этого с помощью дополнительных \ это означает , что:

  • замена должна содержать два символа обратной косой черты \\
  • и строковый литерал, который представляет \\ выглядит как "\\\\"

НО поскольку мы хотим replacement чтобы удержать два обратная косая черта, которая нам понадобится "\\\\\\\\" (каждый \ представленный одним "\\\\").

Итак, версия с replaceAll может выглядеть как

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

Более простой способ

Чтобы упростить жизнь, Java предоставляет инструменты для автоматического экранирования текста в target и replacement части.Итак, теперь мы можем сосредоточиться только на строках и забыть о синтаксисе регулярных выражений:

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

который в нашем случае может выглядеть следующим образом

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

Еще лучше

Если нам действительно не нужна поддержка синтаксиса регулярных выражений, давайте не будем привлекать replaceAll вообще.Вместо этого давайте использовать replace.Оба метода заменят ВСЕ targets, но replace не использует синтаксис регулярных выражений.Таким образом, вы могли бы просто написать

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

Вам нужно будет экранировать обратную косую черту в первом аргументе, поскольку это регулярное выражение.Замена (2 - й аргумент - см. Сопоставитель#replaceAll(Строка)) также имеет особое значение обратной косой черты, поэтому вам придется заменить их на:

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

ДА...к тому времени, когда компилятор регулярных выражений увидит шаблон, который вы ему задали, он увидит только одну обратную косую черту (поскольку лексер Java превратил двойной обратный удар в один).Вам нужно заменить "\\\\" с "\\\\", хотите верьте, хотите нет!Java действительно нуждается в хорошем необработанном строковом синтаксисе.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top