SQL Server (SQLCMD)、Python和使用非ASCII字符时的编码问题
我在用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 个回答
看起来你的默认代码页是850或437。别试着猜测代码页是什么:在命令提示符下输入 chcp
可以告诉你系统当前使用的是什么代码页。
用 chcp
或 mode con:
来设置命令处理器的代码页可能没什么用,因为它们只是设置控制台的输出代码页,而不是用于管道或重定向到文件。
如果想在管道中获取unicode(更确切地说,是utf-16)输出,可以使用 cmd /u
:
>>> subprocess.check_output('''cmd /u /c "echo hello\xe1"''').decode('utf16')
'helloá\r\n'
>>>
不过,实际上你可能更好地选择安装一个真正的数据库适配器。
这个问题可能是因为控制台默认使用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()