在 Python 中管道传输 stdout 时设置正确的编码

2024-12-09 08:31:00
admin
原创
76
摘要:问题描述:当通过管道传输 Python 程序的输出时,Python 解释器会对编码感到困惑,并将其设置为 None。这意味着像这样的程序:# -*- coding: utf-8 -*- print u"åäö" 正常运行时可以正常工作,但会失败:UnicodeEncodeError:'as...

问题描述:

当通过管道传输 Python 程序的输出时,Python 解释器会对编码感到困惑,并将其设置为 None。这意味着像这样的程序:

# -*- coding: utf-8 -*-
print u"åäö"

正常运行时可以正常工作,但会失败:

UnicodeEncodeError:'ascii' 编解码器无法对位置 0 处的字符 u' ' 进行编码:序数不在范围内(128)

在管道序列中使用时。

在管道传输过程中,实现此功能的最佳方法是什么?我可以告诉它使用 shell/文件系统/任何其他正在使用的编码吗?

到目前为止我看到的建议是直接修改你的 site.py,或者使用这个 hack 对 defaultencoding 进行硬编码:

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
print u"åäö"

有没有更好的方法使管道正常工作?


解决方案 1:

您的代码在脚本中运行时可以正常工作,因为 Python 会将输出编码为终端应用程序所使用的任何编码。如果您正在使用管道,则必须自行对其进行编码。

经验法则是:始终在内部使用 Unicode。解码您收到的内容,并编码您发送的内容。

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

另一个教学示例是一个 Python 程序,用于在 ISO-8859-1 和 UTF-8 之间进行转换,使中间的所有内容都变为大写。

import sys
for line in sys.stdin:
    # Decode what you receive:
    line = line.decode('iso8859-1')

    # Work with Unicode internally:
    line = line.upper()

    # Encode what you send:
    line = line.encode('utf-8')
    sys.stdout.write(line)

设置系统默认编码不是一个好主意,因为您使用的某些模块和库可能依赖于 ASCII 编码。不要这样做。

解决方案 2:

首先,关于这个解决方案:

# -*- coding: utf-8 -*-
print u"åäö".encode('utf-8')

每次都明确地使用给定的编码进行打印是不切实际的。这会导致重复且容易出错。

sys.stdout更好的解决方案是在程序开始时进行更改,使用选定的编码进行编码。这是我在Python 上找到的一个解决方案:如何选择 sys.stdout.encoding?,特别是“toka”的评论:

import sys
import codecs
sys.stdout = codecs.getwriter('utf8')(sys.stdout)

解决方案 3:

您可能想尝试将环境变量“PYTHONIOENCODING”更改为“utf_8”。我已写了一页关于我遇到此问题的经历。

博客文章摘要:

import sys, locale, os
print(sys.stdout.encoding)
print(sys.stdout.isatty())
print(locale.getpreferredencoding())
print(sys.getfilesystemencoding())
print(os.environ["PYTHONIOENCODING"])
print(chr(246), chr(9786), chr(9787))

给你

utf_8
False
ANSI_X3.4-1968
ascii
utf_8
ö ☺ ☻

解决方案 4:

export PYTHONIOENCODING=utf-8

完成这项工作,但无法在 python 本身上设置它......

我们可以做的是验证是否未设置,并告诉用户在调用脚本之前进行设置:

if __name__ == '__main__':
    if (sys.stdout.encoding is None):
        print >> sys.stderr, "please set python env PYTHONIOENCODING=UTF-8, example: export PYTHONIOENCODING=UTF-8, when write to stdout."
        exit(1)

更新以回复评论:问题仅在管道传输到 stdout 时存在。我在 Fedora 25 Python 2.7.13 中进行了测试

python --version
Python 2.7.13

猫b.py

#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys

print sys.stdout.encoding

运行 ./b.py

UTF-8

运行 ./b.py | less

None

解决方案 5:

我很惊讶这个答案还没有在这里发布

从 Python 3.7 开始,你可以使用以下命令更改标准流的编码reconfigure()

sys.stdout.reconfigure(encoding='utf-8')

您还可以通过添加参数来修改处理编码错误的方式errors

https://stackoverflow.com/a/52372390/15675011

解决方案 6:

从 Python 3.7 开始,我们可以使用 Python UTF-8 模式,通过使用命令行选项 -X utf8:

 python -X utf8 testzh.py

脚本 testzh.py 包含

print("Content-type: text/html; charset=UTF-8
") 
print("地球你好!")

要将 Windows 10 Internet 服务 IIS 设置为 CGI 脚本处理程序,

我们将可执行文件设置为:

"C:Program FilesPython39python.exe" -X utf8 %s

在此处输入图片描述

这对于中文表意文字在浏览器 Microsoft.Edge 上按预期工作,如下图所示:否则,就会发生错误。

在此处输入图片描述

请参阅https://docs.python.org/3/library/os.html#utf8-mode

解决方案 7:

上周我遇到了类似的问题。在我的 IDE(PyCharm)中很容易修复。

以下是我的解决办法:

从 PyCharm 菜单栏开始:文件 -> 设置... -> 编辑器 -> 文件编码,然后设置:“IDE 编码”、“项目编码”和“属性文件的默认编码”全部为 UTF-8,现在她就可以正常工作了。

希望这有帮助!

解决方案 8:

这是 Craig McQueen 答案的一个有争议的净化版本。

import sys, codecs
class EncodedOut:
    def __init__(self, enc):
        self.enc = enc
        self.stdout = sys.stdout
    def __enter__(self):
        if sys.stdout.encoding is None:
            w = codecs.getwriter(self.enc)
            sys.stdout = w(sys.stdout)
    def __exit__(self, exc_ty, exc_val, tb):
        sys.stdout = self.stdout

用法:

with EncodedOut('utf-8'):
    print u'ÅÄÖåäö'

解决方案 9:

我只是想在这里提一下,我花了很长时间试验才最终意识到发生了什么。这对这里的每个人来说可能都很明显,所以他们没有费心提及它。但如果他们提到了,那会对我有帮助,所以基于这个原则...!

注意:我专门使用的是Jython,v 2.7,所以这可能不适用于CPython ...

NB2:此处我的.py 文件的前两行是:

# -*- coding: utf-8 -*-
from __future__ import print_function

“%”(又称“插值运算符”)字符串构造机制也会导致其他问题……如果“环境”的默认编码是 ASCII,而您尝试执行类似以下操作

print( "bonjour, %s" % "fréd" )  # Call this "print A"

在 Eclipse 中运行时您将不会遇到任何困难...在 Windows CLI(DOS 窗口)中,您会发现编码是代码页 850(我的 Windows 7 操作系统)或类似的东西,至少可以处理欧洲重音字符,所以它可以工作。

print( u"bonjour, %s" % "fréd" ) # Call this "print B"

也可以。

另一方面,如果你从 CLI 直接访问一个文件,那么 stdout 编码将为 None,它将默认为 ASCII(无论如何在我的操作系统上),它将无法处理上述任何一个打印......(可怕的编码错误)。

那么你可能会考虑使用以下方法重定向你的 stdout

sys.stdout = codecs.getwriter('utf8')(sys.stdout)

然后尝试在 CLI 管道中运行文件... 非常奇怪的是,上面的打印 A 可以工作... 但是上面的打印 B 会抛出编码错误!但是下面的操作可以正常工作:

print( u"bonjour, " + "fréd" ) # Call this "print C"

我(暂时)得出的结论是,如果将使用“u”前缀指定为Unicode字符串的字符串提交给 % 处理机制,则它似乎涉及使用默认环境编码,无论您是否已将 stdout 设置为重定向!

人们如何处理这个问题是个人选择的问题。我欢迎 Unicode 专家来告诉我为什么会发生这种情况,我是否在某些方面弄错了,对此的首选解决方案是什么,它是否也适用于CPython,它是否发生在 Python 3 中,等等,等等。

解决方案 10:

我在旧版应用程序中遇到了这个问题,很难确定打印的内容在哪里。我使用了这个技巧来帮助自己:

# encoding_utf8.py
import codecs
import builtins


def print_utf8(text, **kwargs):
    print(str(text).encode('utf-8'), **kwargs)


def print_utf8(fn):
    def print_fn(*args, **kwargs):
        return fn(str(*args).encode('utf-8'), **kwargs)
    return print_fn


builtins.print = print_utf8(print)

在我的脚本 test.py 之上:

import encoding_utf8
string = 'Axwell Λ Ingrosso'
print(string)

请注意,这会将所有打印调用更改为使用编码,因此您的控制台将打印以下内容:

$ python test.py
b'Axwell xcex9b Ingrosso'

解决方案 11:

我可以通过以下调用来“自动化”它:

def __fix_io_encoding(last_resort_default='UTF-8'):
  import sys
  if [x for x in (sys.stdin,sys.stdout,sys.stderr) if x.encoding is None] :
      import os
      defEnc = None
      if defEnc is None :
        try:
          import locale
          defEnc = locale.getpreferredencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.getfilesystemencoding()
        except: pass
      if defEnc is None :
        try: defEnc = sys.stdin.encoding
        except: pass
      if defEnc is None :
        defEnc = last_resort_default
      os.environ['PYTHONIOENCODING'] = os.environ.get("PYTHONIOENCODING",defEnc)
      os.execvpe(sys.argv[0],sys.argv,os.environ)
__fix_io_encoding() ; del __fix_io_encoding

是的,如果这个“setenv”失败,这里可能会出现无限循环。

解决方案 12:

在 Windows 上,我从编辑器(如 Sublime Text)运行 Python 代码时经常遇到这个问题,但从命令行运行则不会遇到。

在这种情况下,请检查编辑器的参数。对于 SublimeText,此方法Python.sublime-build可解决问题:

{
  "cmd": ["python", "-u", "$file"],
  "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
  "selector": "source.python",
  "encoding": "utf8",
  "env": {"PYTHONIOENCODING": "utf-8", "LANG": "en_US.UTF-8"}
}
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   984  
  在项目管理领域,CDCP(Certified Data Center Professional)认证评审是一个至关重要的环节,它不仅验证了项目团队的专业能力,还直接关系到项目的成功与否。在这一评审过程中,沟通技巧的运用至关重要。有效的沟通不仅能够确保信息的准确传递,还能增强团队协作,提升评审效率。本文将深入探讨CDCP...
华为IPD流程   0  
  IPD(Integrated Product Development,集成产品开发)是一种以客户需求为核心、跨部门协同的产品开发模式,旨在通过高效的资源整合和流程优化,提升产品开发的成功率和市场竞争力。在IPD培训课程中,掌握关键成功因素是确保团队能够有效实施这一模式的核心。以下将从五个关键成功因素展开讨论,帮助企业和...
IPD项目流程图   0  
  华为IPD(Integrated Product Development,集成产品开发)流程是华为公司在其全球化进程中逐步构建和完善的一套高效产品开发管理体系。这一流程不仅帮助华为在技术创新和产品交付上实现了质的飞跃,还为其在全球市场中赢得了显著的竞争优势。IPD的核心在于通过跨部门协作、阶段性评审和市场需求驱动,确保...
华为IPD   0  
  华为作为全球领先的通信技术解决方案提供商,其成功的背后离不开一套成熟的管理体系——集成产品开发(IPD)。IPD不仅是一种产品开发流程,更是一种系统化的管理思想,它通过跨职能团队的协作、阶段评审机制和市场需求驱动的开发模式,帮助华为在全球市场中脱颖而出。从最初的国内市场到如今的全球化布局,华为的IPD体系在多个领域展现...
IPD管理流程   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用