java regex replace group




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

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

Нет. Perl использует его, и Perl, безусловно, предшествует классу Java Java. Поддержка регулярного выражения Java явно описывается в терминах регулярных выражений Perl.

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

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

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

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

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

В 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?

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

На стороне Perl

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

Причина, по которой это нужно сделать в Perl, заключается в следующем:

  • Perl использует $ как сигил (т.е. символ, прикрепленный к имени переменной).
  • Строковые литералы Perl имеют переменную интерполяцию.
  • Perge regex фактически захватывает группы как переменные $1 , $2 и т. Д.

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

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

Рекомендации

На стороне Java

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

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

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

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





backreference