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 运算符以字节方式工作,因此它们是 不是多字节安全的,多字节可能会产生意想不到的结果 字符集。此外,这些运算符通过以下方式比较字符 它们的字节值和重音字符可能不相等 即使给定的排序规则将它们视为平等。

[[:&lt;:]][[:&gt;:]] 正则表达式运算符是单词边界的标记。使用 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 的正则表达式实现,它以字节方式运行并且不是多字节安全的。

【讨论】:

哎哟... - 好的,所以如果我切换到: WHERE wine_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 查询 - 不区分重音的搜索的主要内容,如果未能解决你的问题,请参考以下文章

JPA CriteriaQuery - 不区分重音

如何使用 PredicateBuilder、EF Core 5 和 Postgresql 10+ 执行不区分大小写和重音的 LIKE(子字符串)查询?

AWS Aurora MySQL 5.7.12 重音敏感排序规则

可以使 REPLACE() 不区分重音(é = e)吗?

sql网络服务的编辑器怎么调出来

MySQL:查询中的整理 - 任何副作用?