String.replaceAll (regex) делает одну и ту же замену дважды - PullRequest
41 голосов
/ 22 декабря 2011

Может кто-нибудь сказать мне, почему

System.out.println("test".replaceAll(".*", "a"));

Результаты в

aa

Обратите внимание, что следующий результат имеет тот же результат:

System.out.println("test".replaceAll(".*$", "a"));

Я проверил это на Java 6 и 7, и оба, похоже, ведут себя одинаково. Я что-то упустил или это ошибка в движке Java Regex?

1 Ответ

60 голосов
/ 22 декабря 2011

Это не аномалия: .* может соответствовать чему угодно.

Вы просите заменить все вхождения:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...