Вы правы насчет жадности обоих, но ". *"
сопоставляет две строки: первая - "foo"
, а второй - ""
. «. +»
будет соответствовать только «foo»
.
Оба пытаются сопоставить самую длинную строку, которая является «foo»
. После этого они пытаются найти самую длинную совпадающую строку после предыдущего совпадения. На этом этапе ". *"
может соответствовать пустой строке, а ". +"
- нет.
Проверено экспериментально: сопоставитель replaceAll не будет соответствовать дважды в одной позиции строки без продвижения.
Эксперимент:
System.out.println("foo".replaceAll(".??", "[bar]"));
Вывод:
[bar]f[bar]o[bar]o[bar]
Пояснение:
Образец . ??
- это нежадное совпадение 0 или 1 символа, что означает, что оно не будет соответствовать ничему по предпочтению и одному символу, если это будет принудительно. На первой итерации ничего не соответствует, а replaceAll
заменяет ""
на "[bar]"
в начале строки. На второй итерации снова ничего не будет найдено, но это запрещено, поэтому вместо этого один символ копируется из входа в выход ( «f»
), позиция увеличивается, совпадение повторяется, и т.д., так что у вас есть bar - f - bar - o - bar - o - bar: одна "[bar]" для каждого отдельного места, где может быть сопоставлена пустая строка. В конце нет возможности продвинуться вперед, поэтому замена завершается, но только после соответствия «последней» пустой строке.
Ради любопытства Perl делает нечто очень похожее, но применяет правило по-другому. , что дает результат "
хм, Python в обоих случаях производит 'bar'
:
>>> import re
>>> re.sub('.+', 'bar', 'foo')
'bar'
>>> re.sub('.*', 'bar', 'foo')
'bar'
Я предполагаю, что жадный . *
сначала соответствует всей строке, а затем начинает искать совпадение с текущей позиции (конец строки) и соответствует пустой строке перед уходом.
Я думаю, что в первом раунде оба шаблона (. +
и . *
) соответствуют всей строке ( «foo»
). После этого оставшийся ввод, представляющий собой пустую строку, будет соответствовать шаблону . *
.
Однако я обнаружил довольно странный результат из следующих шаблонов.
^.* => 'bar'
.*$ => 'barbar'
^.*$ => 'bar'
Вы можете объяснить, почему он возвращает указанное выше результат? Чем отличается начальная строка ( ^
) от конечной строки ( $
) в регулярном выражении?
Update.1
Я пытаюсь изменить входную строку на следующую строку.
foo
foo
Пожалуйста, посмотрите новый результат!
'^. *' =>
bar
foo
'. * $' =>
foo
barbar
Итак, я думаю, для каждого ввода есть только одна начальная строка. С другой стороны, когда функция находит строку соответствия во входной строке, PS. Вы можете быстро попробовать его на http://gskinner.com/RegExr/
Это действительно интересный вопрос.
Если подумать, String.replaceAll (...)
логически мог быть реализован для выполнения одной из трех задач в случае «. *»:
Очевидно, что последняя альтернатива не является полезно, поэтому я могу понять, почему они этого не сделали. Но мы не знаем, почему они выбрали «варварскую» интерпретацию вместо «барной». Проблема в том, что не существует универсального стандарта для синтаксиса Regex, а есть только семантика Regex. Я предполагаю, что автор (ы) Sun сделал одно из следующего:
Но, в конце концов, это не имеет особого значения. ПОЧЕМУ они выбрали «варвар». Дело в том, что они сделали ... и нам просто нужно с этим разобраться.
Мердад уже объяснил, что он также соответствует одной пустой подстроке в конце строки. Я нашел официальное объяснение этого поведения (зачем сравнивать одну пустую подстроку вместо бесконечного числа) в документации .net:
http://msdn.microsoft.com/en-us/library /c878ftxe.aspx
Quantifiers *, +, {n, m} (и их "ленивый" аналоги) никогда не повторяются после пустого совпадения, когда было найдено минимальное число n. Это правило не позволяет кванторам входить в бесконечные циклы при пустых совпадениях, когда m бесконечно (хотя правило применяется, даже если m не бесконечно).
Например, (a?) * Соответствует строке «aaa» и захватывает подстроки в узор (а) (а) (а) (). Обратите внимание, что пятого пустого захвата нет, потому что четвертый пустой захват заставляет квантификатор перестать повторяться.