我有一个带有字符串的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.
这个ê角色是EAUTF-8 C3 AA.
另一个例子:西班牙语颠倒的问号(¿)就像C8 83 E2 80 9A C3 82 C2那里解码一样,C3 3F 82 BF再次不是正确的UTF-8(翻译成FF 82 BF).预期的特征¿是BF,即C2 BF正确的UTF-8.
这里发生了什么?角色怎么搞砸了?更重要的是,我该如何解决?
(旁注 - 新服务器要求我写mysql_set_charset("utf8");,否则字符串也会搞乱,虽然在"UTF-8 as latin1"时尚,但不是如上所示的这种奇怪的方式.)
TL; DR:
C3 83 C6 92 C3 82 C2 AA
Run Code Online (Sandbox Code Playgroud)
这看起来非常像UTF-8,所以如果我们解码它,我们就会得到
C3 3F C2 AA
Run Code Online (Sandbox Code Playgroud)
如果您将字节序列视为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
Run Code Online (Sandbox Code Playgroud)
通过另一轮对待UTF-8字节和编码到cp1252,你会得到:
C3 AA
Run Code Online (Sandbox Code Playgroud)
最后,这是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')).