我有一个包含一些不良数据的MySQL数据库。
我从这个Unicode字符串开始:
u'TECNOLOGÍA Y EDUCACIÓN'
为数据库编码为UTF-8产生:
'TECNOLOG\xc3\x8dA Y EDUCACI\xc3\x93N'
当我将这些字节发送到数据库时,使用连接字符集latin1
和数据库字符集utf8
(是的,我知道这是错误的,但这已经发生了很多次,并且现在的目标是弄清楚腐败的确切过程,以便可以逆转),数据转换为此(使用BINARY()
检查):
'TECNOLOG\xc3\x83\xc2\x8dA Y EDUCACI\xc3\x83\xe2\x80\x9cN'
除了双重编码之外,我期望的结果是:
'TECNOLOG\xc3\x83\xc2\x8dA Y EDUCACI\xc3\x83\xc2\x93N'
大部分都是有意义的,因为它将多字节UTF-8字符解释为latin1,并将每个字节编码为单个字符,但转换为\x93
- > \xe2\x80\x9c
毫无意义。 latin1的\x93
未转换为UTF-8 \xe2\x80\x9c
,但\xe2\x80\x9c
可以转换为Unicode,产生u'\u201c'
,这是CP中的代码点\x93
1252 charset。
在处理转换时,mysql是否结合了latin1和CP-1252?如何在python中完全复制转换过程?我已经迭代了系统上的每个编码,但它们都不适用于整个字符串。在python中,我如何从'TECNOLOG\xc3\x83\xc2\x8dA Y EDUCACI\xc3\x83\xe2\x80\x9cN'
返回到'TECNOLOG\xc3\x8dA Y EDUCACI\xc3\x93N'
?解码为UTF-8将正确处理前3/4,但最后一个是错误的,我尝试的任何内容都不会返回正确的结果。
答案 0 :(得分:2)
现在的目标是弄清楚腐败的确切过程,以便可以逆转
正如ALTER TABLE
Syntax所述:
警告
CONVERT TO
操作会在字符集之间转换列值。如果您在一个字符集中有一列(如latin1
),则这不是您想要的,但存储的值实际上使用其他一些不兼容的字符集(如utf8
)。在这种情况下,您必须为每个此类列执行以下操作:ALTER TABLE t1 CHANGE c1 c1 BLOB; ALTER TABLE t1 CHANGE c1 c1 TEXT CHARACTER SET utf8;
这样做的原因是当您转换为BLOB列或从BLOB列转换时没有转换。
在你的情况下:
将列的编码更改为插入时使用的连接字符集(即latin1
),以便存储的字节与最初接收的字节相同:
ALTER TABLE my_table MODIFY my_column TEXT CHARACTER SET latin1;
然后删除编码信息(通过修改列使其成为二进制字符串):
ALTER TABLE my_table MODIFY my_column BLOB;
然后应用正确的编码信息(通过修改列使其成为utf8
字符集中的字符串):
ALTER TABLE my_table MODIFY my_column TEXT CHARACTER SET utf8;
小心使用足够长的数据类型以避免数据截断。还要注意确保应用程序代码从此使用正确的连接字符集(否则你最终会得到一个表,其中某些记录以一种方式编码而另一些记录以另一种方式编码,这可能是解决的噩梦)。
如果您还不能修改数据库,只需在连接字符设置为latin1
(但您的应用程序需要UTF-8)时获取数据,就会产生正确的数据。或者,使用CONVERT()
:
SELECT CONVERT(BINARY CONVERT(my_column USING latin1) USING utf8)
FROM my_table
mysql在处理转换时是否合并了latin1和cp1252?
正如West European Character Sets所述:
MySQL的
latin1
与Windowscp1252
字符集相同。这意味着它与官方ISO 8859-1
或IANA(互联网号码分配机构)latin1
相同,但IANAlatin1
处理0x80
和{{1}之间的代码点除外作为“未定义”,而0x9f
,因此MySQL的cp1252
,为这些位置分配字符。例如,latin1
是欧元符号。对于0x80
中的“未定义”条目,MySQL会将cp1252
转换为Unicode0x81
,0x0081
转换为0x8d
,0x008d
转换为0x8f
},0x008f
到0x90
,0x0090
到0x9d
。