【问题标题】:Character encoding issue when using Python3/mysqlclient to retreive data encoded in latin1使用 Python3/mysqlclient 检索以 latin1 编码的数据时的字符编码问题
【发布时间】:2020-02-11 12:18:21
【问题描述】:

从使用latin1 编码的旧数据库中检索数据时,我遇到了字符编码问题。当我尝试从数据库中检索位于\x80\x9f 范围内的字符时,就会出现问题,这是 MySQL 的 latin1(在 Python 中又称为 windows-1252)和官方 @ 之间的不同范围。 987654326@ (ISO-8859-1)。

这是我正在使用的堆栈:

  • MySQL 数据库服务器版本 5.1,在列级别使用 latin1 编码,在表级别使用 latin1-swedish-ci 排序规则。
  • 使用 Python3 的 Django 版本 2.2 和 mysqlclient 版本 1.4.4。

例如,我试图从撇号编码为\x92 的数据库中检索单词“Isn't”。

如果我没有通过 Django 设置将字符集传递给 mysqlclient 连接,则会收到错误消息“'utf-8' codec can't decode byte 0x92 in position 5: invalid start byte”。

如果我将 latin1 作为编解码器传递给连接,则不会出现错误,但该单词会以“Isn t”的形式呈现到页面上,并且撇号应该是空格。

当我打开一个单独的 python shell 会话并尝试从 python 命令行连接时,结果是“Isn\x92t”。

>>> import MySQLdb
>>> conex = MySQLdb.connect(host=<host>,db=<db>, user=<user>, passwd=<passwd>, charset="latin1")
>>> cursor = conex.cursor()
>>> cursor.execute("select <field> from <table> where id=<id>")
1L
>>> cursor.fetchall()
((u'Isn\x92t',),)

从命令行进行调用时是否包含字符集似乎没有任何区别。所以这个连接字符串

>>> conex = MySQLdb.connect(host=<host>,db=<db>, user=<user>, passwd=<passwd>, charset="latin1")

还有这个连接字符串

>>> conex = MySQLdb.connect(host=<host>,db=<db>, user=<user>, passwd=<passwd>)

结果相同。

有没有办法为 mysql 连接字符串设置选项以正确处理 windows-1252 代码?任何帮助将不胜感激。

========= 编辑附加信息 =========

感谢您的回复瑞克·詹姆斯。原始文本 sn-p 消失了,但我发现了另一个类似的失败的文本:Women's。

这是十六进制选择:

mysql> SELECT title, HEX(title) from <table> where id = <id>
| title | HEX(title)
| Women?s | 576F6D656E9273

我不确定将整个 create table 语句放到网上是否合适,但我认为这是 SHOW CREATE TABLE 的重要部分。如果您正在寻找其他东西,请告诉我。

CREATE TABLE `tbl` (
  `title` varchar(255) DEFAULT NULL,
) ENGINE=MyISAM AUTO_INCREMENT=9460 DEFAULT CHARSET=latin1 

最后是SHOW VARIABLES LIKE 'char%'; 结果:

+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | latin1                     |
| character_set_connection | latin1                     |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | latin1                     |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |

将 Django 数据库设置文件中的字符集修改为 utf8mb4 会导致与设置为 utf8 时相同的 unicode 错误。

'OPTIONS': {
  'charset': 'utf8mb4',
  'use_unicode': True,
}

对于为什么使用带有mysqlclient 的独立python 环境的直接查询不起作用,我仍然有点困惑。这至少可以排除任何 Django 问题。

【问题讨论】:

    标签: python mysql django python-3.x character-encoding


    【解决方案1】:

    这些字符集 cp1250, cp1251, cp1256, cp1257, geostd8, latin1 将 x92 视为

    Django 的设置应该指定你想在客户端使用的字符编码。这与数据库中的内容无关。所以问题变成了“配置错误的地方。”

    u 介绍人错误,因为 92 不是有效的 UTF-8。

    • 在列级别进行 latin1 编码 -- 很好
    • 0x92 在数据中——通过SELECT col, HEX(col) ... 进行验证; Isn't 应该说49736E9274
    • 如果您想在客户端使用 UTF-8,Python 源代码应以 # -*- coding: utf-8 -*- 开头。
    • Django 在客户端需要这个 utf8mb4:

      DATABASES = {
          'default': {
              'ENGINE': 'django.db.backends.mysql',
              ...
              'OPTIONS': {
                          'charset': 'utf8mb4',
                          'use_unicode': True, },
          },
      }
      

    如需更多帮助,请提供

    SHOW CREATE TABLE ...;
    SHOW VARIABLES LIKE 'char%';
    the SELECT HEX mentioned above
    

    补充说明(问题被大大扩展后)

    Woman?s -- 请参阅Trouble with UTF-8 characters; what I see is not what I stored 中的问号 -- 这可能是由于连接 (char%) 为 latin1,但客户端 (DJango) 使用的是 utf8mb4。 3 个 char% 设置声明了 client 用于编码的内容; DJango 的设置与此相矛盾。改变一个或另一个。表格列不需要匹配它们;数据将根据需要进行转换。也就是说,即使 character_client/connection/results = utf8mb4,latin1 列中的 92 也是可以的。

    对于这个问题,utf8 和 utf8mb4 的作用相同。

    【讨论】:

    • 数据库中所有与连接相关的字符集设置都设置为'latin1',但是当我尝试将Django设置文件中的'charset'选项设置为'latin1'时,会打印空格的撇号。这似乎与用于解码来自 mysql 的数据的错误 latin1 一致(即使用真正的 latin1 而不是 latin1 的 MySQL 版本)。我应该尝试其他一些设置吗?或者 Django 设置中 charset 选项的其他值?
    • MySQL 中 latin1 中的斜撇号是十六进制 92,所以我不相信这种解释。我怀疑 Django 和 char... 需要同意。在 utf8mb4 上尝试两者。
    • 我根本无法修改数据库。对字符集的任何调整都需要在客户端进行。
    • @Sanjuro - 在客户端,执行SET NAMES utf8mb4,同时将Django配置为utf8mb4。
    猜你喜欢
    • 2019-06-25
    • 2011-07-29
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 2017-06-19
    相关资源
    最近更新 更多