使用 REGEXP (MySql) 在单词边界内查询带有字符串 start/end 的记录

Querying records that start/end with a string, within word boundaries using REGEXP (MySql)

在下面的查询中,我想查找以 engineer 开头的记录。例如我想提取描述为 engineering

的记录
SELECT * FROM app.desc_test t
WHERE lower(t.desc) REGEXP '[[:<:]]engineer[[:>:]]';

单词边界正确处理了所有特殊字符(即前后的逗号、空格、特殊字符等),但我不确定如何编写 Regex 以便 工程师开始。

此外,我如何让这个说法以工程师开头或以工程师结尾。

CREATE TABLE desc_test (
  id int(11) NOT NULL AUTO_INCREMENT,
  desc varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

编辑
该值将为 unknown/dynamic,因此硬编码任何 "ing" 表达式都不是解决方案。

注意:首选 引用的全文搜索

because using REGEXP is thousands of times slower than an indexed solution

但是...

要使用您当前的 REGEXP 实现,您的 MySQL 应该如下所示:

SELECT * FROM app.desc_test t WHERE lower(t.desc) 
REGEXP '[[:<:]]engineer[a-z]*[[:>:]]';

正则表达式如下所示:

[[:<:]]engineer[a-z]*[[:>:]]

含义:

[[:<:]] - Start of word boundary
engineer - The string given by the search (dynamic)
[a-z] - any character between a-z between zero and any number of times.
* - The above "group" between zero and any number of times.
[[:>:]] - End of word boundary

以上内容应该可以满足您的需要。您还可以对其进行自定义,例如包含数字 ((a-z0-9)) 或您想要的任何内容。


对此答案的修订:

一个:

修订、改进:使用[[:alpha:]] 所以:

[[:<:]]engineer[[:alpha:]]*[[:>:]]

两个:

正如 所言,实际上几乎不需要多余的 REGEXP。您的字词界限或缺乏界限会为您完成工作。

因此,对于 select 以 engineer 开头或以 engineer 结尾的任何单词,您只需制作一个 REGEXP OR 语句:

SELECT * FROM app.desc_test t WHERE lower(t.desc) 
REGEXP '([[:<:]]engineer)|(engineer)[[:>:]])' 

这意味着:

Return 如果:

则为真
  • 术语 engineer 出现在单词的开头,无论其后面是什么。
  • OR 术语 engineer 出现在单词的末尾,无论是什么在它之前。

这应该完全符合您的要求。这已经在 MySQL 5.7 上进行了测试。


来源:

  • MYSQL 5.7 Manual
  • MySQL REGEXP word boundaries [[:<:]] [[:>:]] and double quotes

案例:

Engineer

Match

Engineering

Match

Engineers

Match

Engineer!

Match


Also, how would I make this say starts with OR ends with engineer.

只需翻转 REGEXP 并将其设置为 OR 语句:

SELECT * FROM app.desc_test t WHERE lower(t.desc) 
REGEXP '[[:<:]](engineer[[:alpha:]]*)|([[:alpha:]]*engineer)[[:>:]]';

这告诉 REGEXP:
"look for engineer at the beginning of the word followed by any a-z values or look for any a-z values followed by engineer at the end of the word"

如果您只想匹配单词的开头,只需从正则表达式中删除 [[:>:]]

SELECT * FROM app.desc_test t
WHERE lower(t.desc) REGEXP '[[:<:]]engineer';

对于"desc starts with":

“开头为:

REGEXP:  '^engineer...'
LIKE:    'engineer%...'

案例折叠:

If the collation of the column is `..._ci`, then do _not_ waste time with `LOWER()`.

因此,这对于查找 、"engineer" 或 "engineering" 或 "Engineer" 等开头的 desc 是最佳选择:

   WHERE t.desc LIKE 'engineer%'

如果你的意思是"where desc contains 'engineer' or ...",那么

   WHERE t.desc REGEXP '[[:<:]]engineer'

但更好的方法是使用 FULLTEXT(desc) 并使用它;它允许单词出现在 desc 中的任何位置,并且 desc 可以是 TEXT.

   WHERE MATCH(desc) AGAINST('+engineer*' IN BOOLEAN MODE)

您必须根据实际需求进行选择。同时,这是它们的相对性能:

  • LOWER(desc) ... -- 差,不考虑子句的其余部分
  • LIKE 'engineer%' -- 如果你有 INDEX(desc)
  • 那就太好了
  • LIKE 'engineer%' -- 很差,没有索引,或者有前缀:INDEX(desc(100))
  • MATCH... -- 由于 FULLTEXT 索引非常好。
  • REGEXP ... -- 差;将检查每条记录

对于"there is a word that starts or ends with":

您需要列出正面和负面测试用例:

engineering blah
The engineer.
MechanicalEngineering  -- neither starts nor ends at word boundary??
engineer

如果所有这些都有效,那么这是唯一可行的答案:

    WHERE t.desc LIKE '%engineer%'

等效的REGEXP 'engineer'速度较慢(但效果相同)。

对于其他情况,我会看一些接近

的东西
   WHERE t.desc REGEXP '[[:<:]]engineer|engineer[[:>:]]'

查找以 'engineer' 开头或结尾的 "word"。请注意,这不包括 'MechanicalEngineering'.