【问题标题】:Python UnicodeDecodeError - How to correctly read unicode strings from subprocess?Python UnicodeDecodeError - 如何从子进程中正确读取 unicode 字符串?
【发布时间】:2018-11-13 11:13:09
【问题描述】:

我遇到了 Python 中返回 unicode 字符的子进程的问题,尤其是德语 ü、ä、ö 字符。

我的脚本基本上想打开一个子进程,它返回一些带有stdout.read() 函数的字符串。其中一些字符串可能包含 unicode 字符,但并不总是知道这些字符是否以及在哪里。所以必须以某种方式对输出进行解码(或编码?)才能正确显示字符串。 我无法使用字节对象。

以下代码简而言之显示了我尝试执行的操作,但无法解码字符串,因此出现“UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 12: invalid start byte”错误消息:

import subprocess

command_array = ['echo', 'string_with_ü_ä_ö']
command = subprocess.Popen(command_array, stdout=subprocess.PIPE, shell=True)

command_output = command.stdout.read()
command_output = command_output.decode()
print(command_output)

我觉得必须有一些琐碎的解决方案来解决这个问题,但我在任何地方都找不到。有什么方法可以正确返回字符串中的那些 unicode 字符?

我使用的是 Python 3.6.3,上面的脚本在 Windows 上运行。在 Linux 下也能运行的版本将同样受到赞赏!

【问题讨论】:

  • 你确定编码是utf-8而不是iso-8859-1吗?
  • 另请注意,一旦找到正确的编码,您可以将其作为encoding 参数传递给 Popen,然后它将自动为您解码为 str。
  • 传递令牌列表与shell=True 根本不兼容,尽管它可能在您的平台上或多或少地发生了错误。
  • 感谢您的回复!所以它不是 iso-8859-1,因为它只返回空格而不是字符。有没有办法找到正确的编码,还是我必须手动尝试?
  • 如果您的 Python 脚本的编码不是 UTF-8,那么您显然不会要求 shell 输入 echo UTF-8 字符。如果您已为 UTF-8 设置了所有内容,则应该没问题。

标签: python unicode subprocess


【解决方案1】:

我通过反复试验发现使用cp850 进行解码可以正常工作并产生预期的输出:

import subprocess

command_array = ['echo', 'string_with_ü_ä_ö']
command = subprocess.Popen(command_array, stdout=subprocess.PIPE, shell=True)

command_output = command.stdout.read()
command_output = command_output.decode('cp850')
print(command_output)

如果您将上述代码保存为utf8 编码文件(无论平台如何,python3 的默认值)并使用 python3 运行它会打印:

string_with_ü_ä_ö

不幸的是,我不知道在哪里或为什么选择这种特定的编码,所以这可能不适用于不同的设置,但至少我相信它适用于你的设置。

【讨论】:

  • 在一般情况下,不能保证或期望此特定代码页适合您的系统。见(再次)stackoverflow.com/questions/31469707/…
  • @tripleee 我所知道的是,在我的盒子里,输出是用特定的编码(或类似的编码)编码的,在其他类似的情况下。错误消息告诉我,它与 OP 相同。正如我所说,我不知道这种编码来自哪里或它依赖于什么。我没有方便的 windows 框,但我很确定这不是 python open 使用的编码,而是latin 的一些变体。
【解决方案2】:

对于 Python >= 3.6,您需要 subprocess.run()universal_newlines=True

import subprocess

command_array = ['echo', 'string_with_ü_ä_ö']
result = subprocess.run(command_array,
    stdout=subprocess.PIPE, universal_newlines=True)
print(result.stdout)

在 Python 3.7 中,universal_newlines 别名被替换为 text,这更好地解释了该选项的实际作用。

【讨论】:

  • 要(更多)了解所有这些意味着什么,另请参阅stackoverflow.com/a/51950538/874188
  • 也许您的 Windows 代码页有些奇怪? stackoverflow.com/questions/31469707/…
  • 我试过了(添加了shell=True),它给了我以下错误:“UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 12: character maps to
  • shell=True 在这里绝对是完全错误的,正如之前的评论中已经详述的那样。如上所述,你能弄清楚你的 Windows 产生了什么字符集,以及 Python 脚本的编码是什么?
  • 哦,如果只是为了获取echo,因为您没有使用该名称的外部工具,请将echo 替换为其他名称。我想它只是一个更复杂的东西的占位符。为了争论,尝试['python', '-c', 'print("Hällö")']而不是添加Windows命令shell的邪恶。
猜你喜欢
  • 2018-11-14
  • 1970-01-01
  • 2011-04-14
  • 1970-01-01
  • 2011-06-22
  • 1970-01-01
  • 2016-05-26
  • 1970-01-01
  • 2012-05-22
相关资源
最近更新 更多