我有一个包含两列的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,它指出正则表达式引擎按字节顺序工作。因此,我正在寻找一种解决方法。
答案 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。