我必须重新设计一个类,其中(其中包括)UTF-8字符串被错误地双重编码:
$string = iconv('ISO-8859-1', 'UTF-8', $string);
:
$string = utf8_encode($string);
这些错误的字符串已保存到MySQL数据库的多个表字段中。受影响的所有字段都使用归类utf8_general_ci
。
通常我会设置一个小PHP补丁脚本,循环通过受影响的表,选择记录,在双编码字段上使用utf8_decode()
更正错误记录并更新它们。
由于这次我得到了许多大桌子,这个错误只会影响德国变音符号(äöüßÄÖÜ),我想知道是否有更智能/更快的解决方案。
以下的纯MySQL解决方案是否安全且值得推荐?
UPDATE `table` SET `col` = REPLACE(`col`, 'ä', 'ä');
任何其他解决方案/最佳做法?
答案 0 :(得分:20)
更改表格以将列字符集更改为Latin-1。您现在将具有单独编码的UTF-8字符串,但是坐在其校对应该是Latin-1的字段中。
您所做的是,通过二进制字符集将列字符集更改回UTF-8 - 这样MySQL就不会在任何时候转换字符。
ALTER TABLE MyTable MODIFY MyColumn ... CHARACTER SET latin1
ALTER TABLE MyTable MODIFY MyColumn ... CHARACTER SET binary
ALTER TABLE MyTable MODIFY MyColumn ... CHARACTER SET utf8
(正确的语法是iirc;将适当的列类型放在...
所在的位置)
答案 1 :(得分:13)
我尝试了发布的解决方案,但我的数据库不断出现错误。最终我偶然发现了以下解决方案(在我认为的论坛中,但我不记得在哪里):
UPDATE table_name SET col_name = CONVERT(CONVERT(CONVERT(col_name USING latin1) USING binary) USING utf8);
它起了作用。希望这可以帮助那些在我这里绝望的谷歌搜索过来的人。
注意:这当然是假设您的双重编码字符问题源于从latin1到utf8的过度有用的MySQL转换,但我相信大多数这些“损坏的字符”都会发生。这基本上做了与上面提到的相同的转换回到latin1,然后二进制,然后到utf8(使用二进制步骤作为防止已经编码的latin1实体的重新编码的方式)
答案 2 :(得分:7)
我发现以下方法更简单:
mysqldump -h DB_HOST -u DB_USER -p --skip-set-charset --default-character-set=latin1 DB_NAME > DB_NAME-dump.sql
然后删除所有表并使用以下命令重新导入:
mysql -h DB_HOST -u DB_USER -p --default-character-set=utf8 DB_NAME < DB_NAME-dump.sql
在此网址找到提示: http://blog.hno3.org/2010/04/22/fixing-double-encoded-utf-8-data-in-mysql/
答案 3 :(得分:1)
MySql是charset意识,因此您可以在SQL中进行转换。但对于这种情况,我可能更喜欢用PHP编写脚本,因为它无论如何都是一次性的任务。
请记住,MySql中的列具有charset属性。整理(理论上)与字符集正交。虽然utf8_general_ci
排序规则暗示该字符集为utf8
,但它不是给定的。理论上你可以将utf8校对与latin1编码混合在一起(并因此得到垃圾)。
如果您决定在SQL中执行此操作,请查看此处:
答案 4 :(得分:0)
MySQL提供正则表达式匹配,但没有正则表达式替换,所以通常最好迭代遍历php中的每一行,根据需要进行转换,如果已经更改了行,则更新该行。
答案 5 :(得分:0)
使用mysqldump生成转储,更改编码声明(在第一个命令中),然后在另一个数据库中重新加载。
您还可以使用转储上的iconv对其进行转码。
你可以选择INTO OUTFILE,使用php或iconv按摩文件,然后加载数据INFILE。