Почему REGEXP_LIKE не распознаёт границы слов?

Возникла проблема с поиском границ слов с помощью REGEXP_LIKE.

Следующий запрос возвращает одну строку, как и ожидалось:

select 1 from dual
where regexp_like('DOES TEST WORK HERE','TEST');

But I want to match on word boundaries as well. So, adding the "\b" characters gives this query

Но хотелось бы, чтобы поиск осуществлялся и по границам слов. То есть, если добавить символы \b в следующий запрос:

select 1 from dual
where regexp_like('DOES TEST WORK HERE','\bTEST\b');

То он больше не вернёт одну ожидаемую запись.

Какие есть идеи?


Свободный перевод вопроса Oracle REGEXP_LIKE and word boundaries от участника @Greg Reynolds


Ответы (2 шт):

Автор решения: 0xdb

Полагаю, что надо сделать так:

 select 1 from dual 
 where regexp_like ('does test work here', '(^|\s)test(\s|$)');

Это потому, что \b не упоминается в списке Perl-influenced Extensions in Oracle Regular Expressions.

Символ \s обеспечивает, чтобы искомое слово начиналася и заканчивалось пробелом. Однако этого недостаточно, так как искомое слово может оказаться в самом начале или конце полной строки. Поэтому использую альтернативу (на это указывает символ |) ^ для начала строки и $ для конца строки.


Обновление (спустя 3 года+) ...
Так совпало, что недсавно потребовалась эта функциональность, и кажется, что еще лучше регулярное выражение (^|\s|\W)test($|\s|\W) (см. блог Отсутствующий специальный символ регулярного выражения \b в Oracle).


Свободный перевод ответа от участника @René Nyffenegger

→ Ссылка
Автор решения: 0xdb

Самый короткий шаблон, который заменит границу слова \b, т.е. найдёт целое слово, это:

(^|\W)test($|\W)

См. воспроизводимый пример на regex101.

Подробней

  • (^|\W) - группа захвата, совпадающая либо с
    • ^ - начало строки
    • | - или
    • \W - несловарный символ
  • test - само слово
  • ($|\W) - группа захвата, совпадающая либо с
    • $ - конец строки
    • | - или
    • \W - несловарный символ.

Заметьте, что \W соответствует любым символам, кроме букв, цифр и _. Если надо найти слово, которое заключено между _ (подчеркиваниями), то нужен немного другой шаблон:

(^|[^[:alnum:]])test($|[^[:alnum:]])

Отрицаемое выражение во внутренних скобках [^[:alnum:]] совпадёт с любым символом (куда входит _), кроме алфавитно-цифровых, поэтому _test_ будет найден этим шаблоном.

См. воспроизводимый пример на regex101.


Свободный перевод ответа от участника @Wiktor Stribiżew

→ Ссылка