Python 和 MySQL 中的字符编码和解码

Character encoding and decoding in Python with MySQL

查询:

SHOW VARIABLES LIKE 'char%';

MySQL 数据库 returns:

character_set_client    latin1
character_set_connection    latin1
character_set_database  latin1
character_set_filesystem    binary
character_set_results   latin1
character_set_server    latin1
character_set_system    utf8
character_sets_dir  /usr/local/mysql-5.7.27-macos10.14-x86_64/share/charsets/

在我的 Python 脚本中:

conn = get_database_connection()
conn.setdecoding(pyodbc.SQL_CHAR, encoding='latin1')
conn.setdecoding(pyodbc.SQL_WCHAR, encoding='latin1')

对于具有以下值的列之一:

N’a pas

Python returns:

N?a pas

在N和a之间,有一个星形的问号。我如何按原样阅读它?处理它的最佳方法是什么?我一直在阅读有关将我的数据库转换为 utf-8 的文章,但这似乎是一个很可能会破坏其他事物的远景。有没有更有效的方法呢?

在代码的一些地方,我已经做到了:

value = value.encode('utf-8', 'ignore').decode('utf-8')

处理 utf-8 重音字符之类的数据,但 apostrophe 没有得到相同的处理,我最终得到 ? 而不是 '

从长远来看,将数据库转换为 UTF-8 更好 运行,但有风险,因为您可能会像您所说的那样破坏其他内容。您可以做的是将数据库 connection 编码更改为 UTF-8。这样您就可以从数据库中获取 UTF-8 编码的字符串,而无需更改数据的实际存储方式。

conn.setdecoding(pyodbc.SQL_CHAR, encoding='utf8')
conn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf8')

如果这看起来风险太大,但您可以考虑使用两个单独的数据库连接,原始的和 utf8 中的一个,然后逐步将应用程序迁移到使用 utf8是时候测试了。

如果这看起来太冒险,也许可以尝试使用更类似于 mysql 版本的 latin1 的字符编码。 MySQL 的 "latin1" 实际上是 cp1252 encoding 的扩展版本,它本身是 Python(以及其他)中使用的 "standard latin1" 的 Microsoft 扩展。

conn.setdecoding(pyodbc.SQL_CHAR, encoding='cp1252')
conn.setdecoding(pyodbc.SQL_WCHAR, encoding='cp1252')

不要使用任何形式的encoding/decoding;它只会使您的代码复杂化并隐藏更多错误。事实上,您可能正在尝试 "make two wrongs make a right".

使用 utf8(或 utf8mb4)。

关于 "question mark" 的注释:
关于 Python 的注释:http://mysql.rjweb.org/doc.php/charcoll#python