我有一个MySQL数据库,其中包含一些错误数据。
我从这个 Unicode 字符串开始:
U'TECNOLOGÍA Y EDUCACIÓN'
将数据库编码为 UTF-8 会产生:
'TECNOLOG\xc3\x8dA Y EDUCACI\xc3\x93N'
当我使用连接字符集latin1
和数据库字符集utf8
将这些字节发送到数据库时(是的,我知道这是错误的,但这已经发生了很多很多次,现在的目标是找出损坏的确切过程,以便可以逆转(,数据被转换为这个(使用 BINARY()
检查(:
x8dA Y EDUCACI\xc3\x83\xe2\x80\x9cN'
撇开双重编码不谈,我在这里期望的结果是:
'TECNOLOG\xc3\x83\xc2\x8dA Y EDUCACI\xc3\x83\xc2\x93N'
其中大部分是有道理的,因为它将多字节 UTF-8 字符解释为 latin1,并将每个字节编码为单个字符,但 x93
-> xe2x80x9c
的转换毫无意义。 latin1 的x93
不会转换为 UTF-8 xe2x80x9c
,尽管xe2x80x9c
可以转换为 Unicode,产生 u'u201c'
,这是 CP-1252 字符集中的代码点x93
。
mysql 在处理转换时是否结合了 latin1 和 CP-1252?如何完全在 python 中复制转换过程?我已经遍历了系统上的每个编码,但它们都不适用于整个字符串。在python中,我如何才能从'TECNOLOGxc3x83xc2x8dA Y EDUCACIxc3x83xe2x80x9cN'
回到'TECNOLOGxc3x8dA Y EDUCACIxc3x93N'
? 解码为 UTF-8 将正确处理前 3/4,但最后一个是错误的,我尝试过的任何内容都不会返回正确的结果。
-
现在的目标是找出腐败的确切过程,以便可以扭转它。
如
ALTER TABLE
语法中所述:警告
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?
如西欧字符集中所述:
MySQL的
latin1
与Windowscp1252
字符集相同。这意味着它与官方ISO 8859-1
或IANA(互联网号码分配机构(latin1
相同,只是IANAlatin1
将0x80
和0x9f
之间的码位视为"未定义",而cp1252
,因此MySQL的latin1
,为这些位置分配字符。例如,0x80
是欧元符号。对于cp1252
中的"未定义"条目,MySQL将0x81
转换为Unicode0x0081
,0x8d
转换为0x008d
,0x8f
转换为0x008f
,0x90
转换为0x0090
,0x9d
转换为0x009d
。