Это не аномалия: .*
может соответствовать чему угодно.
Вы просите заменить все вхождения:
- первое вхождение соответствует всей строке, поэтому механизм регулярных выражений запускается с конца ввода для следующего совпадения;
- но
.*
также соответствует пустой строке! Поэтому он соответствует пустой строке в конце ввода и заменяет ее на 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
будет считать, что он исчерпал ввод после первого соответствия.