【问题标题】:How to print() a string in Python3 without exceptions?如何在 Python3 中无异常地打印()字符串?
【发布时间】:2014-03-19 02:03:15
【问题描述】:

看似简单的问题:我如何print() Python3 中的字符串?应该很简单:

print(my_string)

但这不起作用。根据my_string 的内容,环境变量和您使用的操作系统将引发UnicodeEncodeError 异常:

>>> print("\u3423")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character '\u3423' in position 0: ordinal not in range(128)

有没有一种干净的便携式方法来解决这个问题?

扩展一下:这里的问题是 Python3 字符串包含 Unicode 编码的字符,而终端可以有任何编码。如果你很幸运,你的终端可以处理字符串中包含的所有字符,一切都会好起来的,如果你的终端不能(例如有人设置LANG=C),那么你会得到一个异常。

如果你在 Python3 中手动编码一个字符串,你可以提供一个错误处理程序来忽略或替换不可编码的字符:

  "\u3423".encode("ascii", errors="replace")

对于print(),我看不到插入错误处理程序的简单方法,即使有,简单的错误处理程序似乎也是一个糟糕的主意,因为它会修改数据。有条件的错误处理程序可能会起作用(即检查isatty() 并根据它决定要做什么),但是仅仅为了print() 一个字符串而经历所有这些麻烦似乎非常糟糕,我什至不确定它不会'在某些情况下不会失败。

一个现实世界的例子,这个问题就是这个问题:

Python3: UnicodeEncodeError only when run from crontab

【问题讨论】:

  • 在 linux 上对我来说很好用。您可能需要指定给您带来麻烦的操作系统和环境变量。
  • 在 Mac OS X 上工作正常。打印出一个(中文?)字符?
  • 在我的 Linux 控制台和 X 终端模拟器上工作,但两者都配置为正确的 UTF-8 支持。我想知道,UTF-8 是否在您收到此错误的环境中一般工作?也许不仅仅是 Python。
  • 如果是 tty,您可以替换 stdout:sys.stdout = io.TextIOWrapper(sys.stdout.detach(), errors='backslashreplace')
  • 使用LANG=C python3 -c 'print("\u3423")',我可以重现您的错误,而使用LANG=en_US.UTF-8,工作正常。

标签: python-3.x python-unicode


【解决方案1】:

有没有一种干净的便携式方法来解决这个问题?

例如设置PYTHONIOENCODING=&lt;encoding&gt;:&lt;error_handler&gt;

$ PYTHONIOENCODING=utf-8 python your_script.py >output-in-utf-8.txt

在您的情况下,我会将您的环境(LANGLC_CTYPE)配置为接受非 ascii 输入:

$ locale charmap

【讨论】:

    【解决方案2】:

    解决这个问题最实用的方法似乎是将输出编码强制为utf-8:surrogateescape。这不仅会强制 UTF-8 输出,还会确保可以打印由os.fsdecode() 返回的代理转义字符串而不会引发异常。在命令行上看起来像这样:

    PYTHONIOENCODING=utf-8:surrogateescape python3 -c 'print("\udcff")'
    

    要在程序本身中执行此操作,必须重新分配 stdoutstderr,这可以通过(line_buffering=True 很重要,否则输出将无法正确刷新):

    import sys
    import io
    
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, errors="surrogateescape", line_buffering=True)
    sys.stderr = io.TextIOWrapper(sys.stderr.buffer, errors="surrogateescape", line_buffering=True)
    
    print("\udcff")
    

    这种方法会导致字符在未设置为 UTF-8 的终端上错误显示,但在我看来,这似乎比随机抛出异常更可取,并且无法在不损坏文件名的情况下打印文件名,因为它们可能不是在 Linux 系统上使用任何有效的编码。

    我在一些地方读到utf-8:surrogateescape 可能会成为未来的默认值,但从 Python 3.6.0b2 开始并非如此。

    【讨论】:

      【解决方案3】:

      它给你一个错误的原因是因为它试图破译 \u 是什么。就像 \r 是用于回车的 ascii,\n - 换行符 \t - 制表符等...

      如果:

       my_string = '\u112'
       print(my_string)
      

      这会给你一个错误,打印'\'而不试图找出\是这样的:

       my_string = '\\u122'
       print(my_string)
      

      输出:

       \u122
      

      【讨论】:

        猜你喜欢
        • 2020-01-31
        • 2017-02-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多