代码之家  ›  专栏  ›  技术社区  ›  Filipe Ferminiano

当我使用拉丁-1编码将utf8编码字符从pandas发送到mysql时,编码字符错误

  •  0
  • Filipe Ferminiano  · 技术社区  · 8 年前

    当我用拉丁-1编码从pandas发送utf8编码字符到mysql时,我得到了错误的编码字符。

    Biquíni
    

    这是我的代码:

    df.breakdown_name = df.breakdown_name.str.encode('latin-1')
    
    send_data(DB_ENGINE, MYSQL_USER, MYSQL_PASSWORD, MYSQL_HOST, MYSQL_PORT, MYSQL_DB, MYSQL_TABLE, df)
    
    def send_data(db, db_user, db_password, db_host, db_port, db_name, db_table, df):
        """
            Return data
                 1
        """
        # print db
        # print db_user
        # print db_password
        # print db_host
        # print db_port
        # print db_name
        # print query[0:20]    
        SQL_ENGINE = '{db}://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}?charset={encoding}'.format(
          db=db,
          db_user=db_user,
          db_password=db_password,
          db_host=db_host,
          db_port=db_port,
          db_name=db_name,
          encoding='latin1',
        )
        engine = create_engine(SQL_ENGINE)    
        df.to_sql(name=db_table,con=engine,schema='xxx',if_exists='append', index=False, chunksize=50)
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   MaximTitarenko    8 年前

    我假设样本值应该是:

    print u'Biquíni'.encode('latin_1').decode('utf-8') # Biquíni
    

    因此,在您的代码中,您正在进行逆变换:

    print u'Biquíni'.encode('utf-8').decode('latin_1') # Biquíni
    

    问题是,在实施链时:

    1. 将unicode编码为“utf-8”字节。
    2. 使用任何1字节编码(如“latin_1”)解码这些字节。

    对于输入的每个非ASCII unicode字符,您将 总是接收错误字符 在输出端。这是因为对于这样的字符,“utf-8”中至少有2字节的值。

    让我们看一下示例:

    print ord(u'z') # 122 => ASCII
    print repr(u'z'.encode('utf-8')) # 'z', 1 byte
    print repr('z'.decode('latin_1')) # u'z'
    

    正如我们所看到的,对于ASCII字符,一切都很好,但是:

    print ord(u'í') # 237 => non-ASCII
    
    import unicodedata
    
    print repr(u'í') # u'\xed'
    print unicodedata.name(u'\xed') # LATIN SMALL LETTER I WITH ACUTE
    
    print repr(u'\xed'.encode('utf-8')) # '\xc3\xad' => 2 bytes
    
    print repr('\xc3'.decode('latin_1')) # u'\xc3' - the 1st char 
    print repr('\xad'.decode('latin_1')) # u'\xad' - the 2nd char
    
    print unicodedata.name(u'\xc3') # LATIN CAPITAL LETTER A WITH TILDE
    print unicodedata.name(u'\xad') # SOFT HYPHEN
    

    因此,在您的代码中,对于在中编码后的每个非ASCII字符 'utf-8' 得到2个字节,然后用 'latin_1' 分为两个字符,它们与初始字符不对应。

    因此,程序的当前方案将产生不希望的结果。
    我建议使用相同的编码 encode() decode() 代码中的步骤。