Backreferences синтаксис в замену строк (почему знак доллара?)
-
04-10-2019 - |
Вопрос
В 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
, и т. Д., Чтобы сделать эту работу беспрепятственно с остальным языком.
использованная литература
- Wikipedia / String Litalal - переменная интерполяция
- Википедия / Сигил (компьютерное программирование)
На стороне Java
Java - это совсем другой язык, чем Perl, но самое главное вот то, что нет вариабельной интерполяции. Кроме того, replaceAll
это вызов метода, и, как и во всех вызовах метода в Java, аргументы оцениваются один раз, до того, как вызываемый метод.
Таким образом, функция переменной интерполяции само по себе недостаточно, поскольку по сути, строка замены должна быть переоценена на каждом матче, и это просто не семантика вызовов метода в Java. Переменная интерполированная замена строки, которая оценивается до то replaceAll
даже вызывается практически бесполезно; Интерполяция должна случиться в течение Способ, на каждом матче.
Так как это не семантика языка Java, replaceAll
должен сделать это «просто вовремя» интерполяция вручную. Отказ Как таковой, есть абсолютно никакой технической причины Зачем $
это символ побега для обратных условий в замену строк. Это могло бы очень хорошо было \
. Отказ И наоборот, обратные условия в шаблоне могут быть также сбежены с $
вместо \
, И все равно будет работать так же хорошо технически.
Причина, по которой Java делает Regex так, как это делает чисто традиционным: это просто после прецедента, установленного Perl.