SQL Server (SQLCMD)、Python和使用非ASCII字符时的编码问题

3 投票
2 回答
2657 浏览
提问于 2025-04-17 05:34

我在用Python代码处理SQL Server 2005的数据时遇到了编码问题。

(因为我无法编译PyMSSQL-2.0.0b1,所以我使用了这段代码,现在可以进行一些查询,但我遇到了一个问题,就是不知道SQLCMD给我输出的是什么 :(

(我需要处理包含欧洲语言的表格,所以需要面对一些带重音符号的其他编码问题)

举个例子:

  • 当我在MS SQL Server管理工作室中读取(选择)时,看到的国家名称是:'Ceská republika'(注意第一个a上有重音符号)
  • 在Windows 7的命令行(Powershell)中使用SQLCMD时,情况也不错,我可以看到"Cesk'a with acute'"
  • 但是当我用Python和os.popen这个方法,使用以下连接字符串时:

    sqlcmd -U adminname -P password -S servername -d dbname /w 8192 -u

我得到的字符串是:'Cesk\xa0 republika'

注意到\xa0这个字符,我不知道它是什么编码,也不知道怎么把\xa0转换成{带重音符号的a}...

如果我在Python中测试,使用unicode,我应该得到这个'\xe1'

>>> unicode('Cesk\xa0 republika')

Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    unicode('Cesk\xa0 republika')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 4: ordinal not in range(128)

>>> unicode_a_with_acute = u'\N{LATIN SMALL LETTER A WITH ACUTE}'
>>> unicode_a_with_acute
u'\xe1'
>>> print unicode_a_with_acute
á
>>> print unicode_a_with_acute.encode('cp1252')
á
>>> unicode_a_with_acute.encode('cp1252')
'\xe1'
>>> print 'Cesk\xa0 republika'.decode('cp1252')
Cesk  republika
>>> print 'Cesk\xa0 republika'.decode('utf8')

Traceback (most recent call last):
  File "<pyshell#21>", line 1, in <module>
    print 'Cesk\xa0 republika'.decode('utf8')
  File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
 UnicodeDecodeError: 'utf8' codec can't decode byte 0xa0 in position 4: invalid start byte

那么SQLCMD给我输出的是什么呢?我该如何强制os.popen等工具确保我得到的是Python可以理解的utf8编码?

(注意,我尝试过在os.popen命令中加上和不加上-u选项,-u应该是让SQLCMD以unicode格式回答,但没有效果。我还尝试过用一个用utf8编码的"select"字符串来输入,也没有成功:

 sqlstr = unicode('select * from table_pays where country_code="CZ"')
 cu = c.cursor
 lst = cu.execute(sqlstr)
 rows = cu.fetchall()
 for x in rows:
      print x

 ( 'CZ          ', 'Cesk\xa0 republika       ')

还有一点:根据我在网上查到的关于"sqlcmd.exe"的信息,还有一些参数可能会有帮助:

[ -f < codepage > | i: < codepage > [ < , o: < codepage > ] ]

但我无法确定哪个是正确的,我不知道可能的值是什么,顺便提一下,使用(或不使用)这个:

[ -u unicode output]

也没有帮到我...

2 个回答

0

看起来你的默认代码页是850或437。别试着猜测代码页是什么:在命令提示符下输入 chcp 可以告诉你系统当前使用的是什么代码页。

chcpmode con: 来设置命令处理器的代码页可能没什么用,因为它们只是设置控制台的输出代码页,而不是用于管道或重定向到文件。

如果想在管道中获取unicode(更确切地说,是utf-16)输出,可以使用 cmd /u

>>> subprocess.check_output('''cmd /u /c "echo hello\xe1"''').decode('utf16')
'helloá\r\n'
>>> 

不过,实际上你可能更好地选择安装一个真正的数据库适配器。

0

这个问题可能是因为控制台默认使用ascii模式,而输出内容是根据当前的代码页设置进行转换的。你可以尝试以下方法,首先把结果写入一个单独的文件,使用:-o <file> -u

这样生成的结果文件就会有正确的ucs2编码,Python可以很高兴地处理这个文件。另一种方法是设置控制台输出为utf8(这个方法还没有测试过):

# setup utf8 on windows console
cmode = 'mode con: codepage select=65001 > NUL & '
cmd = 'my command'
f = os.popen(cmode + cmd)
out = f.readlines()

撰写回答