我有一个带有字符串的MySQL,我暂时休眠了一段时间。现在我再次拾起它,我注意到所有特殊字符都搞砸了。我的ISP已将服务器移植到另一台机器上,我怀疑这可能发生在它发生的时候。
数据库由PHP脚本填充。一切都应该是UTF-8,这就是数据库的设置。
但是,这就是字符串现在的样子:
fête
这四个特殊字符应该是一个字符ê
,字符串应该是fête
。
现在看来这只是重新编码两次,但这似乎不对。十六进制中的这四个字符是:
C3 83 C6 92 C3 82 C2 AA
这看起来非常像UTF-8,所以如果我们解码它,我们就会得到
C3 3F C2 AA
这不是UTF-8(因为3F
),但让我们再次解码:
FF AA
这不是UTF-8。
ê
字符EA
,格式为C3 AA
,格式为¿
。
另一个例子:西班牙语颠倒的问号(C8 83 E2 80 9A C3 82 C2
)与C3 3F 82 BF
一样,解码为FF 82 BF
,这不再是正确的UTF-8(转换为¿
)。 BF
的预期字符为C2 BF
,即正确的UTF-8中的mysql_set_charset("utf8");
。
这里发生了什么?角色怎么搞砸了?更重要的是,我该如何解决?
(旁注 - 新服务器要求我写{{1}}或者字符串也搞乱了,虽然在“UTF-8 as latin1”的方式中,不是如上所示的这种奇怪的方式。)< / p>
TL; DR:
答案 0 :(得分:8)
C3 83 C6 92 C3 82 C2 AA
这看起来非常像UTF-8,所以如果我们解码它,我们就会得到
C3 3F C2 AA
如果将字节序列视为UTF-8,则将其编码为ISO-8859-1。 3F
是?
,已作为替换字符包含在内,因为UTF-8 C6 92
是U + 0192 ƒ
,在ISO-8859-1中不存在。但它确实存在于Windows代码页1252西欧,编码非常类似于ISO-8859-1;那里,它是字节0x83。
C3 83 C2 AA
通过另一轮对待UTF-8字节和编码到cp1252,你得到:
C3 AA
最后是ê
的UTF-8。
请注意,即使您明确地将非XML HTML页面作为ISO-8859-1提供服务,由于历史原因令人讨厌,浏览器实际上也会使用cp1252编码。
不幸的是,MySQL没有cp1252编码; latin1
是(正确)ISO-8859-1。因此,您将无法通过转储为latin1然后重新加载为utf8(两次)来修复数据。您必须使用文本编辑器处理脚本,该文本编辑器可以另存为(或者例如在Python file(path, 'rb').read().decode('utf-8').encode('cp1252').decode('utf-8').encode('cp1252')
中)。
答案 1 :(得分:1)
我怀疑你可能会将你的角色存储为latin1(或类似)数据库中的UTF8字符串。这就是为什么你有双重编码&#39;问题。使数据库的CHARSET UTF8应该修复它。也可能需要转储/导入数据,这些都是这样的:
$ mysqldump --default-character-set=latin1 --skip-set-charset --databases xxx > xxx.sql
$ mysql --default-character-set=utf8 < xxx.sql
但这只是一个建议,可能会有效,但在你的具体情况下不必这样做。