子进程标准输出字符串解码不起作用

use*_*074 0 string ascii subprocess utf-8 python-3.x

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

我需要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')
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

如果仔细看,字符串中会包含可读字符(第一个单词是“ analyzing”

我猜测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\
Run Code Online (Sandbox Code Playgroud)

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

import chardet

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

我正在Windows 10上工作,并且正在使用python 3.6(anaconda软件包及其集成的Spyder IDE)。

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

Mar*_*ers 5

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

由于UTF-16始终为每个字符使用2个字节,因此它们的顺序开始变得很重要。编码器可以在两个选项之间进行选择。一个叫Little Endian,另一个Big Endian。通常,编码器会在开始时就包含一个字节顺序标记,以便解码器知道在解码时要使用两个顺序选项中的哪个。

您发布的数据似乎没有包含BOM(我看不到0xFF0xFE字节,但是您的数据看起来确实是使用低端顺序的。这与Windows匹配; Windows始终使用低端顺序的它是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'
Run Code Online (Sandbox Code Playgroud)