MySQL REGEXP查询 - 重音不敏感搜索

时间:2013-01-03 10:43:58

标签: mysql regex diacritics accent-insensitive

我正在寻找一个葡萄酒名称数据库,其中许多都包含重音(但不是统一的,所以类似的葡萄酒可以带或不带重音输入)

基本查询如下所示:

SELECT * FROM `table` WHERE `wine_name` REGEXP '[[:<:]]Faugères[[:>:]]'

将返回标题中带有'Faugères'的条目,但不会返回'Faugeres'

SELECT * FROM `table` WHERE `wine_name` REGEXP '[[:<:]]Faugeres[[:>:]]'

恰恰相反。

我原以为:

SELECT * 
FROM `table` 
WHERE `wine_name` REGEXP '[[:<:]]Faug[eèêéë]r[eèêéë]s[[:>:]]'

可能会做到这一点,但这只返回没有重音的结果。

该字段整理为utf8_unicode_ci,从我读过的内容是它应该如何。

有什么建议吗?!

7 个答案:

答案 0 :(得分:5)

You're out of luck

  

警告

     

REGEXP和RLIKE运算符以字节方式工作,因此它们是   不是多字节安全的,并且可能会产生多字节的意外结果   字符集。另外,这些运算符比较字符   它们的字节值和重音字符可能无法相等   即使给定的校对将它们视为平等。

[[:<:]][[:>:]] regexp运算符是字边界的标记。使用LIKE运算符可以实现的最接近的就是这一行:

SELECT *
FROM `table`
WHERE wine_name = 'Faugères'
   OR wine_name LIKE 'Faugères %'
   OR wine_name LIKE '% Faugères'

正如你所看到的那样,它并不完全等同,因为我将字边界的概念限制在空格中。为其他边界添加更多子句将是一团糟。

您也可以使用全文搜索(尽管它不相同),但您无法在InnoDB表中定义全文索引。(/ p>

你肯定不走运:)


附录:从MySQL 8.0开始这个has changed

  

MySQL使用International Components for Unicode(ICU)实现正则表达式支持,它提供完整的Unicode支持并且是多字节安全的。 (在MySQL 8.0.4之前,MySQL使用Henry Spencer的正则表达式实现,它以字节方式运行,并且不是多字节安全的。

答案 1 :(得分:3)

因为REGEXP和RLIKE是面向字节的,所以你尝试过:

SELECT 'Faugères' REGEXP 'Faug(e|è|ê|é|ë)r(e|è|ê|é|ë)s';

这说明其中一个必须在表达中。请注意,我没有使用加号(+),因为这意味着一个或多个。由于你只想要一个,所以你不应该使用加号。

答案 2 :(得分:1)

utf8_general_ci在排序时看到重音/没有重音之间没有区别。也许这对搜索也是如此。 另外,将REGEXP更改为LIKE。 REGEXP进行二进制比较。

答案 3 :(得分:0)

好的,我在搜索其他内容时偶然发现了这个问题。

返回true。

SELECT 'Faugères' REGEXP 'Faug[eèêéë]+r[eèêéë]+s';

希望它有所帮助。

添加'+'告诉正则表达式查找一个或多个字符。

答案 4 :(得分:0)

为了解决这个问题,我尝试了不同的东西,包括使用二进制关键字或latin1字符集,但无济于事。
最后,考虑到它是一个MySql错误,我最终取代了é和èchars,

像这样:

SELECT * 
FROM `table` 
WHERE replace(replace(wine_name, 'é', 'e'), 'è', 'e') REGEXP '[[:<:]]Faugeres[[:>:]]'

答案 5 :(得分:0)

我遇到同样的问题,试图找到符合下列模式之一的每条记录:'copropriété','copropriete','COPROPRIÉTÉ','Copropri?t?'

REGEXP 'copropri.{1,2}t.{1,2}为我工作。 基本上,.{1,2}将适用于每种情况下字符是1或2字节编码。

说明:https://dev.mysql.com/doc/refman/5.7/en/regexp.html

警告
REGEXP和RLIKE运算符以字节方式工作,因此它们不是多字节安全的,并且可能会产生多字节字符集的意外结果。此外,这些运算符通过字节值比较字符,即使给定的排序规则将重音字符视为相等,重音字符也可能无法比较。

答案 6 :(得分:0)

我有这个问题,并且上面提到了Álvaro的建议。但就我而言,它错过了搜索词是字符串中中间字的那些实例。我去了相当于:

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