【问题标题】:Character encoding and decoding in Python with MySQL使用 MySQL 在 Python 中进行字符编码和解码
【发布时间】:2020-07-22 19:02:44
【问题描述】:

查询:

SHOW VARIABLES LIKE 'char%';

MySQL 数据库返回:

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 返回:

N?a pas

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

在代码中的某些地方,我已经完成了:

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

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

【问题讨论】:

  • (1) “花式”撇号 (右单引号,U+2019)不是 Latin-1 的一部分。升级到 UTF-8 绝对是最好的选择。现在是 2020 年,UTF-8 无处不在。 (2) value.encode('utf8', 'ignore').decode('utf8') 有效果的情况非常少见。排版引号都不是。 99.9% 的情况下,此表达式返回原始的 value 不变。
  • @lenz - UTF-8 会更好。但是,评论不正确。 Hex 92 是“右单引号”的 latin1 编码。
  • @RickJames 这取决于您如何定义“Latin-1”。代码点 0x92 是标准 Latin-1 (ISO-8859-1) 中的控制字符。它是 Windows 代码页 1252(以及其他)中的一个引号,它是对前者的修改,通俗地称为“Windows Latin 1”。我不知道 MySQL 如何定义“Latin-1”;如果是后者,我不会感到惊讶。
  • @lenz - 我认为 MySQL 的 latin1 没有做任何事情来验证它接收到的字节。另一方面,Utf8 对几乎任何具有 8 位字符的 latin1 字符串(包括所讨论的 92 位)都发出尖叫声。
  • @RickJames 这也是真的。除非您知道解释后的字符串应该是什么样子,否则没有验证任何 8 位编码的好方法。

标签: python mysql utf-8 ascii latin


【解决方案1】:

从长远来看,将数据库转换为 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(以及其他)中使用的“标准 latin1”的 Microsoft 扩展。

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

【讨论】:

    【解决方案2】:

    不要使用任何形式的编码/解码;它只会使您的代码复杂化并隐藏更多错误。事实上,您可能正在尝试“两错两错”。

    使用 utf8(或 utf8mb4)。

    关于“问号”的注释:Trouble with UTF-8 characters; what I see is not what I stored
    Python注意事项:http://mysql.rjweb.org/doc.php/charcoll#python

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-03-18
      • 1970-01-01
      • 1970-01-01
      • 2010-10-26
      • 1970-01-01
      • 2019-08-18
      • 2015-12-17
      • 2017-04-01
      相关资源
      最近更新 更多