使用REGEXP(MySql)查询单词边界内以字符串开头/结尾的记录

时间:2019-01-21 17:23:33

标签: mysql regex stemming

在下面的查询中,我想找到以 engineer 开头的记录。例如我想回退描述为 engineer ing

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

单词边界可以正确处理所有特殊字符(例如,前后的逗号,空格,特殊字符等),但是我不确定如何编写正则表达式,使其以开头

此外,我要如何说这句话或以工程师结尾。

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;

修改
该值是未知的/动态的,因此硬编码任何“ ing” 表达式都不是解决方案。

3 个答案:

答案 0 :(得分:2)

如果只想匹配单词的开头,则只需从正则表达式中删除# Play an audio beep. Any audio URL will do. from google.colab import output output.eval_js('new Audio("https://upload.wikimedia.org/wikipedia/commons/0/05/Beep-09.ogg").play()')

[[:>:]]

答案 1 :(得分:1)

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

  

因为使用REGEXP比索引解决方案要慢数千倍

但是...

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

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

正则表达式如下:

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

含义:

  

[[:<:]]-单词边界的开头
    engineer-搜索(动态)给出的字符串
    [a-z]-介于a到z之间的任意字符,介于0到任意次数之间。
     *-上面的“组”在零到任意次数之间。
    [[:>:]]-单词边界的结尾

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


对此答案的修订:

一个:

修订,改进:使用[[:alpha:]],这样:

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

两个:

正确的pointed out by Barmar实际上几乎不需要多余的REGEXP。您的语言界限,或缺乏界限,会为您效劳。

因此,要选择以engineer开头或以engineer结尾的任何单词,只需简单地执行REGEXP OR 语句:

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

这意味着:

在以下情况下返回true:

  • 术语 engineer 出现在单词的开头,无论后面是什么。
  • OR 术语 engineer 出现在单词的末尾,而不管其开头是什么。

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


来源:

示例案例:

Engineer
     

匹配

Engineering
     

匹配

Engineers
     

匹配

Engineer!
     

匹配


  

此外,我要如何说这句话或以工程师结尾。

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

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

告诉REGEXP:
“在单词的开头查找工程师,然后输入任何az值,或者在末尾查找工程师的任何az值“

答案 2 :(得分:1)

对于“ desc开头”:

“开头为:

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%'

如果您的意思是“ desc 包含“工程师”或...的地方”,那么

   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 ...-贫穷;将检查每条记录

对于“有一个以开头的单词”:

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

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”开头或结尾的“单词”。请注意,这不包括“ MechanicalEngineering”。