MySQL REGEXP 查询 - 不区分重音的搜索
Posted
技术标签:
【中文标题】MySQL REGEXP 查询 - 不区分重音的搜索【英文标题】:MySQL REGEXP query - accent insensitive search 【发布时间】:2012-12-17 17:15:00 【问题描述】:我正在查询一个酒名数据库,其中许多都包含重音(但不是以统一的方式,因此可以输入带或不带重音的类似葡萄酒)
基本查询如下所示:
SELECT * FROM `table` WHERE `wine_name` REGEXP '[[:<:]]Faugères[[:>:]]'
这将返回标题中带有“Faugeres”的条目,但不返回“Faugeres”
SELECT * FROM `table` WHERE `wine_name` REGEXP '[[:<:]]Faugeres[[:>:]]'
反之。
我曾想过这样的事情:
SELECT *
FROM `table`
WHERE `wine_name` REGEXP '[[:<:]]Faug[eèêéë]r[eèêéë]s[[:>:]]'
可能会奏效,但这只会返回不带重音符号的结果。
该字段被整理为 utf8_unicode_ci,从我读到的应该是这样的。
有什么建议吗?!
【问题讨论】:
我遇到了同样的问题。看我这里的题目:***.com/questions/33722136/… 【参考方案1】:You're out of luck:
警告
REGEXP 和 RLIKE 运算符以字节方式工作,因此它们是 不是多字节安全的,多字节可能会产生意想不到的结果 字符集。此外,这些运算符通过以下方式比较字符 它们的字节值和重音字符可能不相等 即使给定的排序规则将它们视为平等。
[[:<:]]
和 [[:>:]]
正则表达式运算符是单词边界的标记。使用 LIKE
运算符可以达到的最接近的结果是这一行:
SELECT *
FROM `table`
WHERE wine_name = 'Faugères'
OR wine_name LIKE 'Faugères %'
OR wine_name LIKE '% Faugères'
正如您所见,它并不完全等价,因为我将单词边界的概念限制为空格。为其他边界添加更多子句将是一团糟。
您也可以使用全文搜索(虽然不一样),但您不能在 InnoDB 表中定义全文索引(目前)。
你肯定不走运:)
附录:此has changed 自 mysql 8.0 起:
MySQL 使用 Unicode 国际组件 (ICU) 实现正则表达式支持,它提供完整的 Unicode 支持并且是多字节安全的。 (在 MySQL 8.0.4 之前,MySQL 使用 Henry Spencer 的正则表达式实现,它以字节方式运行并且不是多字节安全的。
【讨论】:
哎哟... - 好的,所以如果我切换到: WHEREwine_name
LIKE '%Faugeres%' 有什么缺点吗?我不记得为什么我们开始使用 REGEXP,但我认为它与搜索整个单词而不是单词中的字符串有关,上面的 like 语句会这样做......
这个解决方案可能不太好,因为如果单词前后有其他字符,它就不起作用,例如:'Faugères.' 'Faugères!' 'Faugères?' '(Faugères´以及许多其他变体。我正在寻找相同的东西:REGEXP 使用单词边界但不区分重音。
mysql 8 仍然没有运气。REGEXP '\\bFaugeres\\b' 不起作用。我的意思是对口音不敏感是行不通的。
@Linga MySQL 8 修复了多字节支持。不希望正则表达式以这种方式处理排序规则:è
和 e
本身是不同的字符。你可能想试试'\\bFaug[eèêéë]r[eèêéë]s\\b'
。【参考方案2】:
因为REGEXP和RLIKE都是面向字节的,你试过了吗:
SELECT 'Faugères' REGEXP 'Faug(e|è|ê|é|ë)r(e|è|ê|é|ë)s';
这表示其中之一必须在表达式中。请注意,我没有使用加号(+),因为这意味着一个或多个。因为你只想要一个,所以你不应该使用加号。
【讨论】:
这应该是答案。【参考方案3】:utf8_general_ci 排序时没有重音/无重音之间的区别。也许这对于搜索也是如此。 此外,将 REGEXP 更改为 LIKE。 REGEXP 进行二进制比较。
【讨论】:
【参考方案4】:为了解决这个问题,我尝试了不同的方法,包括使用二进制关键字或 latin1 字符集,但无济于事。 最后,考虑到这是一个 MySql 错误,我最终替换了 é 和 è 字符, 像这样:
SELECT *
FROM `table`
WHERE replace(replace(wine_name, 'é', 'e'), 'è', 'e') REGEXP '[[:<:]]Faugeres[[:>:]]'
【讨论】:
这可能效率低下,因为它会为表格的每一行计算表达式。只有在读取整个表格后才能应用条件。【参考方案5】:我在尝试查找与以下模式之一匹配的每条记录时遇到了同样的问题:'copropriété'、'copropriete'、'COPROPRIÉTÉ'、'Copropriété'
REGEXP 'copropri.1,2t.1,2
为我工作。
基本上,.1,2
应该适用于任何情况,无论字符是 1 字节还是 2 字节编码。
解释:https://dev.mysql.com/doc/refman/5.7/en/regexp.html
警告 REGEXP 和 RLIKE 运算符以字节方式工作,因此它们不是多字节安全的,并且可能会在使用多字节字符集时产生意外结果。此外,这些运算符通过字节值比较字符,即使给定的排序规则将重音字符视为相等,重音字符也可能不相等。
【讨论】:
【参考方案6】:我有这个问题,并在上面接受了 Álvaro 的建议。但在我的情况下,它错过了搜索词是字符串中的 middle 单词的那些实例。我去了相当于:
SELECT *
FROM `table`
WHERE wine_name = 'Faugères'
OR wine_name LIKE 'Faugères %'
OR wine_name LIKE '% Faugères'
OR wine_name LIKE '% Faugères %'
【讨论】:
【参考方案7】:好的,我只是在搜索其他内容时偶然发现了这个问题。
这返回真。
SELECT 'Faugères' REGEXP 'Faug[eèêéë]+r[eèêéë]+s';
希望对你有帮助。
添加“+”告诉正则表达式查找一个或多个出现的字符。
【讨论】:
以上是关于MySQL REGEXP 查询 - 不区分重音的搜索的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 PredicateBuilder、EF Core 5 和 Postgresql 10+ 执行不区分大小写和重音的 LIKE(子字符串)查询?