subprocess stdout字符串解码不起作用

时间:2017-08-27 21:47:46

标签: string python-3.x utf-8 subprocess ascii

我正在使用以下子进程调用来使用命令行工具。命令行工具的输出不会一次打印,它会立即打印在命令行上,它会在一段时间内生成多行。该工具为bs1770gain,命令为“path \ to \ bs1770gain.exe”“ - i”“\ path \ to \ audiofile.wav”,通过使用--loglevel参数,您可以包含更多数据但你无法删除写入stdout的渐进结果。

我需要stdout来返回一个人类可读的字符串(因此stdout_formatted操作):

with subprocess.Popen(list_of_args, stdout=subprocess.PIPE,  stderr=subprocess.PIPE) as proc:
    stdout, stderr = proc.communicate()
    stdout_formatted = stdout.decode('UTF-8')
    stderr_formatted = stderr.decode('UTF-8')

但是,如果我打印它,我只能将变量视为人类可读的字符串,例如

In [23]: print(stdout_formatted )
      nalyzing ...   [1/2] "filename.wav": 
          integrated:  -2.73 LUFS / -20.27 LU   [2/2] 
      "filename2.wav":         
          integrated:  -4.47 LUFS / -18.53 LU   
      [ALBUM]:
          integrated:  -3.52 LUFS / -19.48 LU done.

In [24]: stdout_formatted 
Out[24]: 'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00g\.......

In [6]: stdout
Out[6]: b'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00g\......

In [4]: type(stdout)
Out[4]: bytes

In [5]: type(stdout_formatted)
Out[5]: str

如果仔细观察,人类可读的字符就在字符串中(第一个字是“分析”

我猜测stdout值需要解码/编码,所以我尝试了不同的方法:

stdout_formatted.encode("ascii")
Out[18]: b'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00g

stdout_formatted.encode("utf-8")
Out[17]: b'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00g\

stdout.decode("utf-8")
Out[15]: 'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00g\

stdout.decode("ascii")
Out[14]: 'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00g\

bytes(stdout).decode("ascii")
Out[13]: 'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00g\

我使用了一个名为chardet的库来检查stdout的编码:

import chardet

chardet.detect(stdout)
Out[26]: {'confidence': 1.0, 'encoding': 'ascii', 'language': ''}

我正在使用Windows 10并且正在使用python 3.6(anaconda软件包和它集成的Spyder IDE)。

我现在紧紧抓住稻草 - 在变量中调用print或者删除stdout字符串中不需要的字节码时,是否可以捕获控制台中显示的内容?

2 个答案:

答案 0 :(得分:5)

您没有UTF-8数据。你有UTF-16数据。 UTF-16为每个字符使用两个字节; ASCII和Latin-1范围内的字符(例如a)仍然使用2个字节,但其中一个字节始终是\x00个NUL字节。

因为UTF-16总是为每个字符使用2个字节,所以它们的顺序开始重要。编码器可以在两个选项之间进行选择;一个被称为Little Endian, the other Big Endian。通常,编码器在一开始就包含Byte Order Mark,以便解码器知道解码时要使用的两个顺序选项中的哪一个。

您发布的数据似乎不包含BOM(我没有看到0xFF0xFE个字节,但您的数据看起来确实使用了小端排序。这是Windows; Windows总是使用little-endian排序为它的UTF-16输出。

如果您的数据确实存在BOM,则可以解码为'utf-16'。如果缺少BOM,请使用'utf-16-le'

>>> sample = b'a\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00'
>>> sample.decode('utf-16-le')
'analyzin'
>>> import codecs
>>> (codecs.BOM_UTF16_LE + sample)
b'\xff\xfea\x00n\x00a\x00l\x00y\x00z\x00i\x00n\x00'
>>> (codecs.BOM_UTF16_LE + sample).decode('utf-16')
'analyzin'

答案 1 :(得分:-2)

你试过了吗?

 str(stdout_formatted).replace('\x00','')