Это не аномалия: .*
может соответствовать чему угодно.
Вы просите, чтобы заменить все вхождения:
- первое появление делает матч всю строку, движок регулярных выражений, следовательно, начинается с конца входа для следующего матча;
- , но
.*
также соответствует пустой строке! Поэтому он соответствует пустой строке в конце ввода и заменяет ее a
.
Использование .+
вместо этого не будет проявлять эту проблему, поскольку это регулярное выражение не может соответствовать пустой строке (для этого требуется хотя бы один символ).
Или используйте .replaceFirst()
только заменить первое вхождение:
"test".replaceFirst(".*", "a")
^^^^^^^^^^^^
Теперь, почему .*
ведет себя, как это делает и не соответствует более чем в два раза (теоретически мог) интересная вещь, чтобы рассмотреть , См. Ниже:
# Before first run
regex: |.*
input: |whatever
# After first run
regex: .*|
input: whatever|
#before second run
regex: |.*
input: whatever|
#after second run: since .* can match an empty string, it it satisfied...
regex: .*|
input: whatever|
# However, this means the regex engine matched an empty input.
# All regex engines, in this situation, will shift
# one character further in the input.
# So, before third run, the situation is:
regex: |.*
input: whatever<|ExhaustionOfInput>
# Nothing can ever match here: out
Обратите внимание, что, как @ A.H. примечания в комментариях, не все двигатели регулярных выражений ведут себя таким образом. Например, GNU sed
будет считать, что он исчерпал вход после первого совпадения.
Согласен. Это верно и для Perl. 'perl -le '$ x =" test "; $ x = ~ s /.*/ a/g; print $ x'' дает «aa». –
@ChrisDolan: 'sed' дает только' a', но я сомневаюсь в его ошибке. :-) –
@ A.H. да, действительно ... Мне нужно снова прочитать «Освоение регулярных выражений» – fge