Восемь обратных косых черт, необходимых для замены одиночной обратной косой черты двойными обратными косыми чертами?

#java #regex #string

#java #регулярное выражение #строка

Вопрос:

Это вопрос «что, черт возьми, здесь происходит». На самом деле мне не нужно решение.

Мне пришлось заменить все одиночные обратные косые черты в строке двойными обратными косыми чертами . Это то, что я в итоге сделал…

 strRootDirectory = strRootDirectory.replaceAll("\\", "\\\\");
  

…где strRootDirectory — это java.lang .Строка выше.

Теперь я понимаю четыре обратных косых черты для первого аргумента: регулярное выражение ожидает две обратные косые черты, чтобы указать одну буквальную обратную косую черту, и java хочет, чтобы они удвоились. Это нормально.

НО, что, черт возьми, происходит с восемью обратными косыми чертами для второго аргумента? Разве строка замены не должна быть буквальной (я имею в виду, нерегулярной) строкой? Я ожидал, что мне понадобится четыре обратных косых черты во втором аргументе, чтобы представить две обратные косые черты.

Комментарии:

1. Да, Java обратная косая черта. Попробуйте Python: re.sub(r"\", r"\\", mystr)

2. Или просто используйте соответствующий инструмент для работы — не используйте регулярные выражения, когда они вам не нужны…

3. Или используйте соответствующую операционную систему для работы — не используйте Windows, если она вам не нужна. Обратите внимание, что Java поддерживает прямые косые черты там, где Windows обычно хотела бы использовать обратную косую черту.

4. Может быть, я переключусь на ручку, бумагу и счеты.

Ответ №1:

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

Из API:

Обратите внимание, что обратная косая черта ( ) и знаки доллара ( $ ) в строке замены могут привести к тому, что результаты будут отличаться от того, если бы они обрабатывались как строка буквальной замены; см. Matcher.replaceAll . Matcher.quoteReplacement(java.lang.String) При желании используйте для подавления специального значения этих символов.

http://download.oracle.com/javase/6/docs/api/java/lang/String.html#replaceAll (…)

Комментарии:

1. ОИК! Я думал, что аргумент два — это дословная строка (т. Е. Без специальных символов), которая должна быть записана вместо строки регулярного выражения аргумента. Спасибо!

2. Нет проблем, Джон. То же самое сбило меня с толку, когда я впервые столкнулся с этим! 🙂

3. @JohnFitzpatrick String.replace() функция принимает 2 дословные строки (без регулярных выражений или специальных символов) см. Мой ответ

4. @ratchet freak, да, replace(...) здесь лучший вариант.

5. @ratchet: Спасибо, что подтвердили мое здравомыслие. Я был уверен, что в какой-то форме замены строки второй аргумент был буквальным.

Ответ №2:

Это проще, если вы используете replace("\","\\") ( String.replace принимает литеральные строки и более эффективен, когда все это литерально)

или вы можете обеспечить корректность с помощью функций Pattern.quote и Matcher.quoteReplacement

Комментарии:

1. Спасибо за предложение. С помощью replace() Мне пришлось бы выполнять цикл до завершения, потому что исходная строка содержит много обратных косых черт, а затем на второй итерации я подозреваю, что первой найденной обратной косой чертой будет та, которую я только что поместил туда из последнего replace() . Я думаю, что бесконечный цикл, если replace() не может отслеживать, что он в последний раз заменял.

2. нет, он «заменяет каждую подстроку этой строки, которая соответствует буквенной целевой последовательности, указанной буквенной последовательностью замены». проверьте ссылку в ответе

Ответ №3:

"\\\\" приводит к представлению в памяти строки с 4 обратными косыми чертами : \\ . Хотя вторая строка не является строкой регулярного выражения, обратная косая черта и знаки доллара по-прежнему являются специальными символами в ней, поэтому их нужно экранировать.

Комментарии:

1. Но замена не является строкой регулярного выражения: другие метасимволы регулярных выражений не нужно экранировать.

2. Это тоже не обычная строка. Смотрите Bart размещенную ссылку.

3. Я знаю, это тот же Барт . 🙂

4. @BartKiers: Ах, извините. Я не смотрел на ваше имя при чтении вашего комментария, я думал, что ОП написал это 🙂

Ответ №4:

Согласно справочным материалам Java, метод replaceAll интерпретирует обратные косые черты в строке замены также как escape-символы. Они могут использоваться для экранирования символа знака доллара, который может ссылаться на совпадающие выражения для повторного использования в строке замены. поэтому, естественно, если вы хотите удвоить количество обратных косых черт, и оба параметра обрабатывают обратную косую черту как escape-символ, вам нужно в два раза больше обратных косых черт в строке замены.

Ответ №5:

Да, это становится сложным, когда вам нужно делать такие вещи, не так ли.

Причина, по которой вам нужно так много обратных косых черт, заключается в том, что вам нужно учитывать, что обратная косая черта используется как для экранирования строки, так и для экранирования регулярного выражения.

  • Возьмите 1 обратную косую черту.
  • Удвойте его для экранирования строки.
  • Удвойте его снова для экранирования регулярных выражений.
  • Удвойте его еще раз, потому что вам нужно сопоставить две последовательные обратные косые черты в исходной строке.

Это составляет 8.

Ответ №6:

Как любитель не вдаваться в сверхдетальные объяснения регулярных выражений… Я понял из основного ответа Барта Кирса выше:

 System.out.println( "line1: " "hello\\world" );
System.out.println( "line2: " "hello\\world".replaceAll("\\\\", Matcher.quoteReplacement("\") ) );
  

выводит

 line1: hello\world
line2: helloworld
  

Надеюсь, это поможет…