2012-02-10 3 views
4

Возник вопрос о регулярном выражении и попытке ответить. Я нашел еще одну странную вещь.Странное поведение в регулярных выражениях

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" s, а не X?

+0

Замена 'X *?' В Perl/PCRE приведет к 'YYY'. – Qtax

ответ

8

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

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

Есть два матча:

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

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

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

Есть также два матча:

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

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

+0

В первом случае, на втором шаге (2. В позиции символа 1 ...), но нет позиции 1, это вне границы строки, не так ли? после первого шага все должно быть закончено, потому что строка закончилась. – shift66

+0

@ Ademiban: Не совсем. Есть позиция '1'. Рассмотрим следующее регулярное выражение: '' $ "'. По определению, * только * место, где он может совпадать, после последнего символа строки. В этом примере это будет в позиции '1'. То же самое происходит с регулярными выражениями, которые могут давать совпадения нулевой длины. – NPE

+0

Отличный ответ! Позвольте мне добавить, возможно, интересную ноту, хотя:) Во втором сценарии X не сопоставляется с *? подразумевает ленивое соответствие, т. е. элементы перед *? предпочтительно не совпадают, если это все еще дает действительный результат. –

1

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

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

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

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

0

В первом примере вы используете квантификатор «Жадный». Это означает, что входная строка принудительно считывается целиком, прежде чем пытаться выполнить первое совпадение, поэтому первое совпадение - это весь ввод. Если вход соответствует, совпадение проходит мимо входной строки и выполняет совпадение нулевой длины в конце строки, следовательно, два совпадения, которые вы видите. Жадный помощник никогда не отступает до нулевой длины перед символом X до того, как первая попытка матча была успешной.

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