【问题标题】:In MySQL, why is a non-ASCII character really two characters?在 MySQL 中,为什么一个非 ASCII 字符真的是两个字符?
【发布时间】:2012-03-13 08:09:19
【问题描述】:

我有一个默认编码设置为 utf8 的 MySQL 数据库。因此,使用非 ASCII 字符应该没有问题。但是,通过 REGEXP 命令处理正则表达式似乎有点困难。

我正在尝试使用通配符根据正则表达式查询记录。 MySQL 提供的功能对我来说已经足够了,但它们似乎有点不正常,因为非 ASCII 字符(我尝试过 § 和 °)不是由一个通配符匹配,而是由两个通配符匹配。

例如,如果我在数据库中搜索名为“§123”的 wiki 页面,那么

SELECT * FROM wikipages WHERE title REGEXP '^.123$'

不会返回任何东西,但是

SELECT * FROM wikipages WHERE title REGEXP '^..123$'

返回所需的页面(注意额外的通配符)。

对于 ASCII 字符,只需要一个通配符。我想这与用多少字节来编码 utf8 中的字符有关。但是,我发现这种行为相当难看,因为如果 MySQL 不平等对待所有字符,我将无法使用正则表达式。

实际上是否有充分的理由说明它不能正常工作?有人知道如何解决我的问题吗?

提前致谢!

【问题讨论】:

  • 在这个简单的例子中,WHERE title LIKE '_123' 可以工作,但在更一般的例子中你会失去 REGEXP 的威力。

标签: mysql regex utf-8


【解决方案1】:

警告

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

http://dev.mysql.com/doc/refman/5.1/en/regexp.html

UTF-8 是一个潜在的多字节字符集。基本上,尝试在正则表达式中针对 UTF-8 字符进行通配符匹配有时会失败。

您可以搜索特定字符(它会自动扩展为正确的字节数),或者您可以使用非正则表达式模式匹配(例如LIKE)进行前缀/后缀搜索。

【讨论】:

  • 感谢您的快速回答。我不想使用LIKE,因为我正在使用没有包装功能的 Django,这意味着我必须自己处理字符转义。但这似乎是最简单的方法。
  • @j0ker 看看contains lookup。它也是escapes % and _
  • @cbuckley 我也想过contains(),但是我需要一个包含LIKE some_word 的查询而不是LIKE %someword%,因为我必须能够准确地指定单词在没有特殊字符的情况下的样子。 contains() 对此无能为力。我在 Django 中发现了一篇关于 LIKE 的博文:yaco.es/blog/en/contribuciones/2012/02/…
【解决方案2】:

需要指明通配符的出现

试试

SELECT "§123" REGEXP "^.*123$" - any character 0 - n
SELECT "§123" REGEXP "^.{0,2}123$" - any character 0 - 2

两个表达式的结果都是 1。此外,MySQL 手册警告多字节字符。

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

【讨论】:

  • 那行得通。但我认为这有点不切实际,因为'^.{0,2}123$' 不仅可以匹配§123 之类的东西,还可以匹配ab123。我希望查询中只放一个字符,不多也不少,所以我猜LIKE 是最好的选择。
猜你喜欢
  • 1970-01-01
  • 2011-10-19
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-20
  • 1970-01-01
相关资源
最近更新 更多