我想列出在本地Windows计算机上运行的服务。为此,我正在使用以下代码:
with Popen(["net", "start"], stdout=PIPE, stderr=PIPE) as p:
stdout, stderr = p.communicate() # type: (bytes, bytes)
输出的一部分看起来像这样(德语Windows版本):
Folgende Windows-Dienste sind gestartet:
Anmeldedienst
[...]
Benachrichtigungsdienst für Systemereignisse
将字节解码为字符串应该很容易。我检查了文档,并在命令行上找到了本地编码:
>>> import locale
>>> locale.getpreferredencoding()
'cp1252'
因此,我想对字节进行解码:
lines = stdout.decode('cp1252')
但是,对于示例中列出的变音符号ü
,我收到一条错误消息:
File "test.py", line 511, in my_func
lines = stdout.decode('cp1252')
File "C:\Python344\lib\encodings\cp1252.py", line 15, in decode
return codecs.charmap_decode(input,errors,decoding_table)
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 152: character maps to <undefined>
但是,我知道UTF-8 contains a representation of the ü
character:
U+00FC ü c3 bc LATIN SMALL LETTER U WITH DIAERESIS
我茫然为什么无法完成翻译。
注意:
universal_newslines=True
进行Popen
通话时,可以规避整个测试过程,但这使我得以分析编码问题所在。Popen
构造函数添加了encoding=
选项,也许这可以避免类似的问题。可悲的是,Python 3.4是某些LTS Linux版本中包含的版本。编辑1:这里有些事。尽管Python 3.4文档指出Windows上的默认编码为cp1252,但是在CLI上运行命令并重定向到文件时,该文件在IBM850中进行了编码。最好的猜测是locale.getpreferredencoding()
不返回CLI的编码。
编辑2:使用ibm850
对标准输出进行解码的过程就像一个超级按钮。这意味着对universal_newlines=True
调用使用Popen
会使用locale.getpreferredencoding()
返回的编码,但是,这是解码CLI输出的错误编码。
答案 0 :(得分:0)
解决方案是:
在universal_newslines=True
中使用locale.getpreferredencoding()
调用时,将强制对返回的stdout stderr数据进行字符串解释。但是,解释是使用cp1252
返回的编码完成的,本例中为cp1252
。但是,命令行上的数据不是使用ibm850
(类似于Windows的ANSI样式编码)进行编码,而是使用ü
(DOS编码)进行编码。因为解码是对字节和int进行运算,并且因为cp1252
解码表中str.decode('ibm850')
(0x81)的stdout中的int没有对应的值,所以抛出了Python深度的异常。>
使用正确解码的Popen
手动解码命令行数据。
注意:从Python 3.5开始, so = StackOverflow(key=input("enter key:"), value=input("enter value:"))
允许传递用于数据流的编码,而Python 3.4缺少该编码。