作者回复: 是的,python3和python2在处理字符编码时,有一些区别。 感谢补充这些内容。
作者回复: 1. MySQL在使用character_set_client指定的编码对数据进行decode时,如果遇到问题,就说明字符集不匹配了。 MySQL并不知道客户端发过来的数据的真实编码,除非使用_charset指定,比如: mysql> SELECT _utf8mb4 0xe4b8ade69687; | 中文 | 2. utf8环境下,如果character_set_client设置为gbk,那么表的字符集为gbk和utf8时,会有不一样的情况。 mysql> create table t_gbk(a varchar(100)) charset gbk; mysql> create table t_utf8(a varchar(100)) charset utf8; mysql> set names gbk; mysql> insert into t_gbk values('中文符号'); mysql> select a, hex(a), char_length(a) from t_gbk; | 中文符号 | E4B8ADE69687E7ACA6E58FB7 | 6 | 写入到t_gbk时,没有做编码转换。虽然看上去没乱码,但是实际上表里存的是“中文符号”的utf8编码。 为了写入t_utf8,需要设置非严格模式 mysql> set sql_mode=''; mysql> insert into t_utf8 values('中文符号'); Query OK, 1 row affected, 1 warning (0.00 sec) mysql> show warnings; | Warning | 1366 | Incorrect string value: '\xAD\xE6\x96\x87\xE7\xAC...' for column 'a' at row 1 | 数据虽然写入了,但是有warning,Incorrect string value里面显示的十六进制串,来自原始数据“中文符号”的utf8编码,'\xe4\xb8\xad\xe6\x96\x87\xe7\xac\xa6\xe5\x8f\xb7' 用gbk decode这串数据时遇到问题了。 mysql> select a, hex(a), char_length(a) from t_utf8; | �?��符号 | E6B6933FE69E83E7BB97EFB980E5BDBF | 6 | 表t_utf8里存的数据是怎么来的呢? >>> '\xe4\xb8\xad\xe6\x96\x87\xe7\xac\xa6\xe5\x8f\xb7'.decode('gbk', errors='replace').encode('utf8') '\xe6\xb6\x93\xef\xbf\xbd\xe6\x9e\x83\xe7\xbb\x97\xef\xb9\x80\xe5\xbd\xbf' 这个数据和表里的数据有一点差异,就是替换符不一样,MySQL中以\x3f作为替换符。python中以\xef\xbf\xbd,也就是u'\ufffd'作为替换符。这其实就是?和�的区别。
作者回复: 完美地还原了事发现场👍👍 这种数据,最好还是要订正回来,否则后患无穷。