Объясните неожиданный результат regexp_replace

Я обнаружил неожиданный результат при использовании regexp_replace для объединения строки в конце другой строки в качестве упражнения по использованию regexp_replace для этого. Я поднимаю его не только для того, чтобы выяснить, почему, но и для того, чтобы сообщить людям об этом, возможно, неожиданном результате.

Рассмотрим это утверждение, в котором намерение состоит в том, чтобы прикрепить «примечание 2» к концу строки «примечание 1». Я намеревался сгруппировать всю строку, а затем объединить новую строку до конца:

select regexp_replace('note 1', '(.*)', '\1' || ' note 2') try_1 from dual;

Но посмотрите на результат:

TRY_1               
--------------------
note 1 note 2 note 2

Примечание повторяется дважды! Почему?

Если я изменю шаблон, включив в него привязки начала и конца строки, он будет работать, как ожидалось:

select regexp_replace('note 1', '^(.*)$', '\1' || ' note 2') try_2 from  dual;

TRY_2        
-------------
note 1 note 2

Почему это должно иметь значение?

РЕДАКТИРОВАТЬ: см. Объяснение Политанка-Z ниже. Я хотел добавить, что если я изменю первый пример, чтобы использовать плюс (соответствует 1 или более вхождений предыдущего символа), а не звездочку (для 0 или более вхождений предыдущего символа), он будет работать, как ожидалось:

select regexp_replace('note 1', '(.+)', '\1' || ' note 2') try_3 from dual;

TRY_3        
-------------
note 1 note 2

person Gary_W    schedule 06.04.2015    source источник


Ответы (1)


Согласно документации Oracle:

По умолчанию функция возвращает source_char с заменой каждого вхождения шаблона регулярного выражения на replace_string.

Ключ там каждый случай. .* соответствует пустой строке, а механизм регулярных выражений Oracle сначала сопоставляет всю строку, а затем следующую пустую строку. Добавляя якоря, вы устраняете это. В качестве альтернативы вы можете указать параметр вхождения в связанной документации.

person Politank-Z    schedule 06.04.2015
comment
Вы можете объяснить, откуда берется пустая строка? Спасибо - person Gary_W; 06.04.2015
comment
Звездочка указывает, что предыдущий атом регулярного выражения встречается ноль или более раз. Учитывая ваше общее регулярное выражение, это означает, что нулевое совпадение - пустая строка - является допустимым совпадением. regexp_replace применяет ваше регулярное выражение один раз, сопоставляя всю строку (см. «Жадный» и «нежадный» в терминах регулярного выражения), затем ищет другое совпадение, начиная с конца предыдущего совпадения. Конец предыдущего совпадения находится после последнего символа, оставляя пустую строку. - person Politank-Z; 06.04.2015
comment
Очень интересно! Я заменил шаблон '. *' На '. +' (Плюс означает соответствие 1 или более, в отличие от звездочки, означающей 0 или более) в первом примере, и он работает, как ожидалось! Спасибо Политанк-З! - person Gary_W; 06.04.2015