pymssql 在 Azure/Windows 上返回的字符集与在 Mac 上不同

Posted

技术标签:

【中文标题】pymssql 在 Azure/Windows 上返回的字符集与在 Mac 上不同【英文标题】:pymssql returns different charset on Azure/Windows than on Mac 【发布时间】:2016-10-23 20:20:44 【问题描述】:

我有一个托管在 Azure 上的 sql server 数据库。我已经用智能引号('“test”')在数据库中放入了一个字符串。我可以连接到它并运行一个简单的查询:

import pymssql
import json

conn = pymssql.connect(
    server='coconut.database.windows.net',
    user='kingfish@coconut',
    password='********',
    database='coconut',
    charset='UTF-8',
)

sql = """
SELECT * FROM messages WHERE id = '548a72cc-f584-7e21-2725-fe4dd594982f'
"""
cursor = conn.cursor()
cursor.execute(sql)
row = cursor.fetchone()
json.dumps(row[3])

当我在我的 Mac(macOS 10.11.6、Python 3.4.4、pymssql 2.1.3)上运行这个查询时,我得到了字符串:

"\u201ctest\u201d"

这被正确解释为智能引号并正确显示。

当我在 Azure Web 部署(Python 3.4,Azure 应用服务)上运行此查询时,我得到了相同字符串的不同(且不正确)编码:

"\u0093test\u0094"

我在 pymssql 连接上将字符集指定为“UTF-8”。为什么 Windows/Azure 环境返回不同的字符集?

(注意:我已将预构建的二进制 pymssql-2.1.3-cp34-none-win32.whl 放在 Azure 上我的项目 repo 的操舵室中。这与 pymssql 预构建的二进制 pymssql- 2.1.3-cp34-cp34m-win32.whl 仅在 PyPI 上我不得不将 'cp34m' 重命名为 'none' 以说服 pip 安装它。)

【问题讨论】:

【参考方案1】:

根据您的描述,我认为问题似乎是由 Azure 上 SQL 数据库的默认字符集编码引起的。为了验证我的想法,我在 Python 3 中做了一些测试。

Azure 上 SQL 数据库的默认字符集编码为 Windows-1252 (CP-1252)。

SQL Server Collation Support Microsoft Azure SQL 数据库使用的默认数据库排序规则是 SQL_LATIN1_GENERAL_CP1_CI_AS,其中 LATIN1_GENERAL 是英语(美国),CP1 是代码页 1252,CI 不区分大小写,AS 区分重音。无法更改 V12 数据库的排序规则。有关如何设置排序规则的详细信息,请参阅 COLLATE (Transact-SQL)。

>>> u"\u201c".encode('cp1252')
b'\x93'
>>> u"\u201d".encode('cp1252')
b'\x94'

如上所示,\u0093 & \u0094 可以通过编码\u201c & \u201d 得到。

还有,

>>> u"\u0093".encode('utf-8')
b'\xc2\x93'
>>> u"\u0093".encode('utf-8').decode('cp1252')[1]
'“'     # It's `\u201c`
>>> u"\u201c" == u"\u0093".encode('utf-8').decode('cp1252')[1]
True

所以我认为你当前用于数据存储的SQL数据库的字符集编码是Latin-1,而不是UTF-8,当你创建SQL数据库时,如下图,Azure门户上的默认属性Collation是@ 987654334@。请尝试使用其他排序规则支持UTF-8 而不是默认的。

【讨论】:

有趣。我正在使用 SQL_Latin1_General_CP1_CI_AS 的默认排序规则。当我在 Mac 上运行“sys.stdin.encoding”时,我得到“utf-8”,而在 Azure 上,我得到“cp1252”。我想知道默认的 python 字符编码是否决定了正在使用的 unicode 字符。只有在启动 Python 之前,我无法弄清楚如何在 Azure 上执行“chcp 65001”...【参考方案2】:

我最终将列类型从 VARCHAR 重铸为 NVARCHAR。这解决了我的问题,无论平台如何,都可以正确解释字符。

【讨论】:

太棒了。感谢您的分享。

以上是关于pymssql 在 Azure/Windows 上返回的字符集与在 Mac 上不同的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Manjaro 上安装 pymssql - 编译问题?

在 OS X 上构建 pymssql

麻烦在 MacOS Mojave 上安装 pymssql

在 Windows 10 上安装 pymssql 时遇到问题

在 Windows 10 上安装 pymssql 时出错

在 Mac OS 10.6 (python 2.6) 上安装/构建 pymssql