7

在 MySQL 中,当在只需要“全词匹配”的文本字段中搜索关键字时,可以使用 REGEXP 以及 [[:<:]] 和 [[:>:]] 词边界标记:

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]word[[:>:]]"

例如,当我们要查找所有包含“欧洲”的文本字段时,使用

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]europe[[:>:]]"

将返回“欧洲地图”,但不返回“欧洲联盟”。

但是,当目标匹配词包含“点字符”时,例如“我们”,我应该如何提交正确的查询?我尝试了以下查询,但没有一个看起来正确。

1.

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]u.s.[[:>:]]"

2.

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]u[.]s[.][[:>:]]"

3.

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]u\.s\.[[:>:]]"

当使用双反斜杠转义特殊字符时,如 d'alar'cop 所建议的,它返回空,即使表中有类似“us congress”的内容

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]u\\.s\\.[[:>:]]"

任何建议表示赞赏!

4

5 回答 5

12

这个正则表达式做你想要的:

SELECT name
FROM tbl_name
WHERE name REGEXP '([[:blank:][:punct:]]|^)u[.]s[.]([[:punct:][:blank:]]|$)'

前面有以下内容时匹配u.s.

  • 空白(空格、制表符等)
  • 标点符号(逗号、括号等)
  • 什么都没有(即在行首)

然后是:

  • 空白(空格、制表符等)
  • 标点符号(逗号、括号等)
  • 什么都没有(即在行尾)

请参阅SQLFiddle,其中包含上述要点的边缘情况。

于 2013-09-01T12:04:39.603 回答
8

谓词的基本问题.是非单词字符,如果它们跟随开始测试或在结束测试之前,任何非单词字符都会导致单词边界测试失败。您可以在此处查看行为。

使问题更加复杂的是,MySQL 使用的正则表达式的风格非常有限。根据Regular-Expressions.info,MySQL 使用POSIX-ERE,如果您阅读底部的图表正则表达式风格比较,与其他风格相比,它的功能很少。

要解决您的问题,您必须创建一个新的正则表达式来替换单词边界的功能,以便允许非单词字符成为边界的一部分。我想出了以下正则表达式:

(^|[^[:alnum:]_])YOUR_TEXT_HERE($|[^[:alnum:]_])

这相当于下面的标准正则表达式:

(^|[^a-zA-Z0-9_])YOUR_TEXT_HERE($|[^a-zA-Z0-9_])

正则表达式在文本的开头和结尾搜索非单词字符或字符串边界。 (^|[^[:alnum:]_])匹配字符串开头、字母数字字符或下划线。结束模式类似,只是它匹配字符串的结尾而不是开头。

该模式旨在最好地匹配MySQL 手册中正则表达式中单词边界的定义:

[Boundaries] 分别匹配单词的开头和结尾。单词是前面或后面没有单词字符的单词字符序列。单词字符是alnum类中的字母数字字符或下划线。

测试结果

使用上面的正则表达式,我想出了一个场景,我测试一个在开头和结尾包含非单词字符的字符串 - .u.s.。我试图想出一套合理的测试项目。您可以在 SQLFiddle查看结果。

测试数据

test string not present:                 'no match' 
missing .'s:                             'no us match' 
missing last .:                          'no u.s match' 
missing first .:                         'no us. match' 
test start boundary word character:      'no.u.s.match'   
test end boundary word character:        'no .u.s.match'   
test boundaries word character:          'no.u.s.match'   
test basic success case:                 'yes .u.s. match' 
test start boundary non-word character:  'yes !.u.s. match'   
test end boundary non-word character:    'yes .u.s.! match'   
test boundaries non-word character:      'yes !.u.s.! match' 
test start of line:                      '.u.s.! yes match'   
test end of line:                        'yes match .u.s.' 

询问

SELECT *
FROM TestRegex
WHERE name REGEXP '(^|[^[:alnum:]_])[.]u[.]s[.]($|[^[:alnum:]_])'; 

SQLFiddle

结论

所有的正面案例都返回了,没有一个负面案例=>所有测试案例都成功了。

  • 您可以使用[.]句点字符代替\\.我发现在 SQL 表达式的上下文中更具可读性。
  • 您可以根据自己的需要调整用于定义边界的集合,使其具有或多或少的限制性。例如,您也可以限制一些非单词字符:[^a-zA-Z_0-9.!?#$].
于 2013-08-31T16:08:56.173 回答
1

这里的工作示例:http ://www.sqlfiddle.com/#!2/5aa90d/9/0

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]u\\.s\\.([^[:alnum:]]|$)"

基本上说我们后面必须跟任何不是字母数字字符或字符串结尾的东西。

如果需要,您可以更改[:alnum:][:alpha:]包含类似This is us5这样的结果。

于 2013-08-29T18:36:40.950 回答
0

只需使用此查询:

SELECT name FROM tbl_name WHERE name REGEXP ""[[:<:]]u\\.s\\.([[:blank:]]|$)"

无需end-of-word [[:>:]]在 RHS 上使用,因为 . 之后已经有一个点s

于 2013-08-09T19:19:13.777 回答
-1

mysql 正则表达式手册中有一个特殊字符表以及如何转义它们。

做你的查询

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]u[.]s[.][[:>:]]"

或者

SELECT name FROM tbl_name WHERE name REGEXP "[[:<:]]u[[.period.]]s[[.period.]][[:>:]]"

将工作

于 2013-08-31T16:34:13.370 回答