Странное поведение в регулярных выражениях - PullRequest
4 голосов
/ 10 февраля 2012

Был вопрос о регулярных выражениях, и, пытаясь ответить, я обнаружил еще одну странную вещь.

String x = "X";
System.out.println(x.replaceAll("X*", "Y"));

Печать YY.почему ??

String x = "X";
System.out.println(x.replaceAll("X*?", "Y"));

И это печатает YXY

Почему неохотное регулярное выражение не соответствует символу X?Существует "noting"X"nothing", но почему сначала не совпадают три символа и совпадают два, а затем один вместо трех?и второе регулярное выражение соответствует только "nothing" с, а не X?

Ответы [ 3 ]

8 голосов
/ 10 февраля 2012

Давайте рассмотрим их по очереди:

"X".replaceAll("X*", "Y")

Есть два совпадения:

  1. В позиции символа 0, X сопоставлено и заменено на Y.
  2. В позиции символа 1 сопоставляется пустая строка, и Y добавляется к выводу.

Конечный результат: YY.

"X".replaceAll("X*?", "Y")

Есть также два совпадения:

  1. В позиции символа 0 сопоставляется пустая строка, и Y добавляется к выводу. Символ в этой позиции, X, не был использован совпадением и поэтому копируется в выходной дословно.
  2. В позиции символа 1, пустая строка сопоставляется, иY добавляется к выводу.

Конечный результат: YXY.

1 голос
/ 10 февраля 2012

* является хитрым «квантификатором», поскольку он означает «0 или более».Таким образом, он также соответствует «0 раз X» (т.е. пустой строке).

Я бы использовал

"X".replaceAll("X+", "Y")

, который имеет ожидаемое поведение.

0 голосов
/ 10 февраля 2012

В первом примере вы используете квантификатор "Жадность".Это означает, что перед попыткой первого сопоставления входная строка должна быть полностью прочитана, поэтому первое пробное совпадение - это весь ввод.Если входные совпадения совпадают, сопоставление проходит мимо входной строки и выполняет сопоставление нулевой длины в конце строки, следовательно, два совпадения, которые вы видите.Жадный сопоставитель никогда не отступает от совпадения с нулевой длиной до символа X до того, как первая попытка сопоставления была успешной.Во втором примере вы используете квантификатор «Reluctant», который противоположен «Greedy».Он начинается с начала и пытается соответствовать одному символу в то время, когда идет вперед (если это необходимо).Таким образом, сопоставление нулевой длины до совпадения символа «X» соответствует, перемещается вперед на единицу (поэтому вы все еще видите символ «X» в выходных данных), где следующее совпадение теперь соответствует совпадению нулевой длины после «X»».Здесь есть хороший учебник: http://docs.oracle.com/javase/tutorial/essential/regex/quant.html

...