Backreferences синтаксис в замену строк (почему знак доллара?)

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

Вопрос

В Java, и кажется на нескольких других языках, обратные условия в шаблоне предшествуют обратной косой (например, \1, \2, \3, и т. Д.), Но в заменной строке они предшествовали знак доллара (например, $1, $2, $3, а также $0).

Вот фрагмент, чтобы проиллюстрировать:

System.out.println(
    "left-right".replaceAll("(.*)-(.*)", "\\2-\\1") // WRONG!!!
); // prints "2-1"

System.out.println(
    "left-right".replaceAll("(.*)-(.*)", "$2-$1")   // CORRECT!
); // prints "right-left"

System.out.println(
    "You want million dollar?!?".replaceAll("(\\w*) dollar", "US\\$ $1")
); // prints "You want US$ million?!?"

System.out.println(
    "You want million dollar?!?".replaceAll("(\\w*) dollar", "US$ \\1")
); // throws IllegalArgumentException: Illegal group reference

Вопросы:

  • Это использование $ Для обратных условий в замену строк уникальные для Java? Если нет, какой язык начал это? Какие ароматы используют это и что нет?
  • Почему это хорошая идея? Почему бы не придерживаться того же синтаксиса шаблона? Разве это не приведет к более сплоченному и легчему изучению языка?
    • Разве синтаксис не будет более упорядоченным, если операторы 1 и 4 в вышеуказанные были «правильными» вместо 2 и 3?
Это было полезно?

Решение

Используется ли $ для обратных условий в замену строк, уникальных для Java?

Нет. Perl использует это, а Perl, безусловно, предложил Java Pattern сорт. Поддержка Regex Java явно описана с точки зрения Regexes Perl.

Например: http://perldoc.perl.org/perlrequick.html#search-and-dreplace.

Почему это хорошая идея?

Ну, очевидно, вы не думаете, что это хорошая идея! Но одна из причин, по которой это хорошая идея, состоит в том, чтобы сделать Java поиск / заменить поддержку (более) совместимым с Perl.

Есть еще одно возможно Причина, почему $ возможно, было рассматриваться как лучший выбор, чем \. Отказ Это что \ должен быть написан как \\ в буквальном литерате Java.

Но все это чистые спекуляции. Никто из нас не был в комнате, когда были сделаны дизайнерские решения. И в конечном итоге это не имеет значения, почему они разработали синтаксис строки замены. Решения были сделаны и установлены в бетоне, и любая дополнительная дискуссия является чисто академическими ... если только вы просто не будете разрабатывать новый язык или новую библиотеку Regex для Java.

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

После каких-то исследований я понял проблемы сейчас: Perl имел Использовать другой символ для образцов обратной панели и замену задних условий, а пока java.util.regex.* нет имеют Чтобы следовать исчезновению, он выбирает, а не для технической, но довольно традиционной причины.


На стороне перл

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

Причина, по которой это имел Для выполнения этого способа в Perl следующее:

  • Perl использует $ в качестве SIGIL (то есть символ, прикрепленный к имени переменной).
  • Литералы Perl String являются переменными интерполированными.
  • Perl Regex фактически захватывает группы в качестве переменных $1, $2, так далее.

Таким образом, из-за того, как Perl интерпретируется, и как работает его двигатель Regex, предшествующая чесука для обратных условий (например, \1) в шаблоне необходимо использовать, потому что если SIGIL $ используется вместо этого (например, $1), это приведет к непреднамеренному переменной интерполяции в шаблон.

Строка замены, из-за того, как она работает в Perl, оценивается в контексте каждого матча. Это наиболее естественно для Perl использовать здесь переменную интерполяцию, поэтому двигатель Regex захватывает группы в переменные $1, $2, и т. Д., Чтобы сделать эту работу беспрепятственно с остальным языком.

использованная литература


На стороне Java

Java - это совсем другой язык, чем Perl, но самое главное вот то, что нет вариабельной интерполяции. Кроме того, replaceAll это вызов метода, и, как и во всех вызовах метода в Java, аргументы оцениваются один раз, до того, как вызываемый метод.

Таким образом, функция переменной интерполяции само по себе недостаточно, поскольку по сути, строка замены должна быть переоценена на каждом матче, и это просто не семантика вызовов метода в Java. Переменная интерполированная замена строки, которая оценивается до то replaceAll даже вызывается практически бесполезно; Интерполяция должна случиться в течение Способ, на каждом матче.

Так как это не семантика языка Java, replaceAll должен сделать это «просто вовремя» интерполяция вручную. Отказ Как таковой, есть абсолютно никакой технической причины Зачем $ это символ побега для обратных условий в замену строк. Это могло бы очень хорошо было \. Отказ И наоборот, обратные условия в шаблоне могут быть также сбежены с $ вместо \, И все равно будет работать так же хорошо технически.

Причина, по которой Java делает Regex так, как это делает чисто традиционным: это просто после прецедента, установленного Perl.

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