Почему это происходит?
Вы по-прежнему соответствуете этим предложениям из-за возврата назад.
Поскольку вы используете [^nN]
, оно все равно может соответствовать blank
или punct
. Итак, вот что происходит (просто используя один из ваших примеров входных данных, чтобы проиллюстрировать это):
Используя Caffeine[:blank:]*[:punct:]*[:blank:]*[^nN]
в качестве примера (все ваши шаблоны действуют одинаково).
User 4: 'Caffeine-No'
^^^^^^^^ matches Caffeine literally
^ matches [:blank:] zero times
^ matches [:punct:] one time
^ matches [:blank:] zero times
^ N doesn't match `[^nN]`, let's backtrack to see if something else works
^ matches [:punct:] zero times
^ matches [:blank:] zero times
^ - matches [^nN]
Good match due to backtracking
В приведенном выше примере регулярное выражение позволяет [^nN]
соответствовать символу -
. Regex хочет, чтобы соответствовал чему-то, поэтому он исчерпает каждую возможность, пока не будет (или не останется и не останется).
Как это исправить?
Одним из способов решения этой проблемы является указание только возможных символов в позиции [^nN]
(что-то вроде [0-9a-mo-z]
и т. Д.), Но это может быстро усложниться. Лучшая альтернатива может быть следующей:
См. Работающий здесь SQL
select * from docs where content REGEXP 'Caffeine[[:blank:]]*[[:punct:]]*[[:blank:]]*[[:<:]][^nN]'
В приведенной выше строке используется [[:<:]]
, чтобы утверждать, что позиция является началомграница слова. Другие языки используют \b
для обозначения того же. Это означает, что он гарантирует, что любой символ, кроме [0-9a-zA-Z_]
, соответствует слева от позиции, и что любой символ в [0-9a-zA-Z_]
соответствует справа от позиции.
В других движках регулярных выражений то же самое может бытьлегко достигается с помощью притяжательных квантификаторов (обычно +
после квантификатора, например .*+
), но MySQL еще не имеет притяжательного токена (AFAIK).