2

我有一个 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,产生CP-1252 字符集中的u'\u201c'代码点。\x93

mysql 在处理转换时是否结合了 latin1 和 CP-1252?如何在 python 中完全复制转换过程?我已经遍历了系统上的每个编码,但它们都不适用于整个字符串。在 python 中,我如何从'TECNOLOG\xc3\x83\xc2\x8dA Y EDUCACI\xc3\x83\xe2\x80\x9cN'back 回到'TECNOLOG\xc3\x8dA Y EDUCACI\xc3\x93N'?解码为 UTF-8 将正确处理前 3/4,但最后一个是错误的,我尝试过的任何方法都不会返回正确的结果。

4

1 回答 1

2
  1. 现在的目标是弄清楚腐败的确切过程,以便扭转它

    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 列转换时没有转换。

    在你的情况下:

    1. 将列的编码更改为插入时使用的连接字符集(即latin1),以便存储的字节与最初接收的字节相同:

      ALTER TABLE my_table MODIFY my_column TEXT CHARACTER SET latin1;
      
    2. 然后删除编码信息(通过修改列使其成为二进制字符串):

      ALTER TABLE my_table MODIFY my_column BLOB;
      
    3. 然后应用正确的编码信息(通过修改列使其成为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
    
  2. mysql 在处理转换时是否结合了 latin1 和 cp1252?

    西欧字符集下所述:

    MySQL 的字符集latin1与 Windowscp1252字符集相同。这意味着它与官方ISO 8859-1或 IANA(Internet Assigned Numbers Authority)latin1相同,除了 IANA将和latin1之间的代码点视为“未定义” ,而 MySQL为这些位置分配字符。例如,是欧元符号。对于 中的“未定义”条目,MySQL 将转换为 Unicode 、to 、to 、to和to 。0x800x9fcp1252latin10x80cp12520x810x00810x8d0x008d0x8f0x008f0x900x00900x9d0x009d

于 2013-08-15T00:51:16.553 回答