如何让MySQL知道LIKE和REGEXP中的多字节字符?

时间:2011-06-26 06:39:58

标签: mysql sql unicode utf-8 character-encoding

我有一个包含两列的MySQL表,两列都是utf8_unicode_ci。它包含以下行。除ASCII外,第二个字段还包含Unicode代码点,如U + 02C8(MODIFIED LETTER VERTICAL LINE)和U + 02D0(MODIFIED LETTER TRIANGULAR COLON)。

 word   | ipa
--------+----------
 Hallo  | haˈloː
 IPA    | ˌiːpeːˈʔaː

我需要使用LIKE和REGEXP搜索第二个字段,但MySQL(5.0.77)似乎将这些字段解释为字节,而不是字符。

SELECT * FROM pronunciation WHERE ipa LIKE '%ha?lo%';  -- 0 rows
SELECT * FROM pronunciation WHERE ipa LIKE '%ha??lo%'; -- 1 row

SELECT * FROM pronunciation WHERE ipa REGEXP 'ha.lo';  -- 0 rows
SELECT * FROM pronunciation WHERE ipa REGEXP 'ha..lo'; -- 1 row

我很确定数据是否正确存储,因为当我检索它并在phpMyAdmin中显示正常时它似乎很好。我在共享主机上,所以我无法真正安装程序。

我该如何解决这个问题?如果不可能:是否有合理的解决方法,不涉及每次都使用PHP处理整个数据库?有40 000行,我并没有使用MySQL(或UTF8,就此而言)。我只能在主机上访问PHP和MySQL。

编辑:有一个开放的4年前的MySQL错误报告Bug #30241 Regular expression problems,它指出正则表达式引擎按字节顺序工作。因此,我正在寻找一种解决方法。

3 个答案:

答案 0 :(得分:9)

已编辑以修复有效的批评

使用HEX()函数将字节呈现为十六进制,然后使用RLIKE,例如:

select * from mytable
where hex(ipa) rlike concat('(..)*', hex('needle'), '(..)*'); -- looking for 'needle' in haystack, but maintaining hex-pair alignment.

奇数unicode字符始终呈现其十六进制值,因此您正在搜索标准的0-9A-F字符。

这也适用于“普通”列,你只是不需要它。

P.S。 @Kieren(有效)点使用rlike来强制执行字符对

答案 1 :(得分:3)

  

我没有使用MySQL

Postgres似乎处理得很好:

test=# select 'ˌˈʔ' like '___';
 ?column? 
----------
 t
(1 row)

test=# select 'ˌˈʔ' ~ '^.{3}$';
 ?column? 
----------
 t
(1 row)

如果你走这条路,请注意Postgres的ilike运算符与MySQL的like匹配。 (在Postgres中,like区分大小写。)


对于MySQL特定的解决方案,您可以通过绑定一些user-defined function(可能将ICU library?绑定到MySQL)来解决这个问题。

答案 2 :(得分:-2)

你有UTF8的问题吗?消除它们。

您使用了多少个特殊字符?你是否只使用locase字母,对吗?所以,我的建议是:编写一个函数,将spec chars转换为常规字符,例如: “æ” - >“A”等,并在表中添加一列,用于存储转换后的值(您必须先转换所有值,并在每次插入/更新时)。搜索时,您只需要使用相同的函数转换搜索字符串,并使用regexp在该字段上使用它。

如果有太多种特殊字符,您应该将其转换为多字符。 1.避免在“ba ab”序列中找到“aa”使用一些前缀,例如“@ ba @ ab”。 2.避免在“@ab”中找到“@a”使用固定长度的令牌,比如2。