2011-12-22 3 views
38

Может кто-нибудь сказать мне, почемуString.replaceAll (регулярное выражение) делает то же замена дважды

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

Результаты в

aa 

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

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

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

ответ

57

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

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

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

+0

Согласен. Это верно и для Perl. 'perl -le '$ x =" test "; $ x = ~ s /.*/ a/g; print $ x'' дает «aa». –

+7

@ChrisDolan: 'sed' дает только' a', но я сомневаюсь в его ошибке. :-) –

+0

@ A.H. да, действительно ... Мне нужно снова прочитать «Освоение регулярных выражений» – fge

Смежные вопросы