使用 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 以便 从 工程师开始。
此外,我如何让这个说法以工程师开头或以工程师结尾。
- 有些 similar issue,但在 .NET 中
- Similar issue,但在 MySQL
中寻找双引号
- MySQL 5.7 正则表达式 docs
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'.
在下面的查询中,我想查找以 engineer 开头的记录。例如我想提取描述为 engineering
的记录SELECT * FROM app.desc_test t
WHERE lower(t.desc) REGEXP '[[:<:]]engineer[[:>:]]';
单词边界正确处理了所有特殊字符(即前后的逗号、空格、特殊字符等),但我不确定如何编写 Regex 以便 从 工程师开始。
此外,我如何让这个说法以工程师开头或以工程师结尾。
- 有些 similar issue,但在 .NET 中
- Similar issue,但在 MySQL 中寻找双引号
- MySQL 5.7 正则表达式 docs
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:]]*[[:>:]]
两个:
正如
因此,对于 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'.