【问题标题】:Printing UTF-8 characters in Python 3 to the web将 Python 3 中的 UTF-8 字符打印到 Web
【发布时间】:2021-01-09 07:56:35
【问题描述】:

我正在尝试将 Python 3 中的 Unicode 字符打印到网络上。在 Python 中我可以运行:

print("Content-Type: text/html; charset=utf-8\n")
print("\u00EA")

从命令行运行时,它会正确吐出:

内容类型:文本/html;字符集=utf-8

ê

但是当在 Apache 下作为 CGI 脚本从 Web 运行时,它会抛出错误:

UnicodeEncodeError: 'ascii' codec can't encode character '\xea' in 位置 0:序数不在范围内(128)

关于如何让 Python 3 将 UTF-8 打印到网络上有什么建议吗?谢谢!

编辑:locale 在我的帐户和www-data(Apache 的帐户)中的输出是:

LANG=en_US.UTF-8
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

【问题讨论】:

  • 只是不要使用printf?配置操作系统区域设置以使用 UTF8?
  • 顺便说一句,这个页面就像所有其他网页一样都是 UTF8。不需要特殊处理,这就是为什么您可以阅读这些越南语字符而无需对其进行编码或联系 SO 的团队要求特殊处理。
  • 运行 apache 进程的用户的区域设置是什么?
  • 问题是 printf 和控制台。您正在写入控制台,而不是文件,这意味着 Python 必须使用控制台的编码。如果您的环境配置为使用 Latin1 或更糟的 US-ASCII,则文本将被破坏。在 Linux 上,这由LC_ALL 控制。 Windows 本身是 UnicodeBUTconsole GUI 是特定于区域设置的,需要设置来显示 UTF8。不过,这不应该影响进程到进程的通信
  • 这个答案看起来像你想要的stackoverflow.com/a/19574801/5320906。选项 4(通过 Apache 的 $LANG 看起来是最好的方法,在其他答案中建议摆弄 sys.defaultencoding 但这很 hacky imo。

标签: python utf-8 python-unicode


【解决方案1】:

感谢这里用户的反馈,我能够拼凑出一个解决方案:

  1. Content-Type 行必须包含 charset=utf-8
  2. Apache 的配置文件必须包含SetEnv LANG en_US.UTF-8

一个很棒的调试工具是打印sys.stdout.encoding 的值,它应该返回“UTF-8”,而不是“ANSI_X3.4-1968”。

【讨论】:

    【解决方案2】:

    您必须将数据显式编码为 utf-8(否则 Python 会尝试猜测,而在您的情况下,它会猜测 ASCII,但效果不佳)。所以,这样做:

    sys.stdout.buffer.write(text.encode('utf-8'))
    

    这将解决您的错误。 请注意,我使用的是sys.stdout.buffer.write 而不是print,因为buffer.write 可以处理原始字节(而UTF-8 是原始字节数组,而不是字符串)。

    除此之外,你应该告诉客户端(浏览器)数据是以utf-8形式提供的(否则浏览器也必须猜测,这可能会成功,但最好是明确的),例如

    print("Content-Type: text/html; charset=utf-8\n")
    

    【讨论】:

    • 这是我尝试过的方法之一,但在命令行和 Web 浏览器上都会出现这种情况:b'L\xc3\xaa Qu\xc3\xbd \xc4\x90\xc3\xb4n \n'
    • Python 3 字符串已经是 Unicode。这更像是一个操作系统/控制台问题。也许操作系统的语言环境配置为使用 ASCII?如果在 Linux 上,LC_ALL 是如何设置的?
    • @NeilFraser 是的,我写的代码太快了,没有检查。它不能与print 一起使用。我确定了答案,尝试一下。
    • @PanagiotisKanavos Python 3 字符串是 unicode,它们不是 UTF-8。它们需要转换为 UTF-8 字节数组。 print 将通过检查stdout 的编码来自动执行此操作,这对于打印到控制台来说是很好的。生成 HTTP 响应应该更明确地说明编码。
    【解决方案3】:

    当您读取文件时使用上下文管理器。

    后台打开和关闭文件已为您完成,因此您不必记住它。

    with open(filename , encoding='utf-8') as f:
        text = f.read()
    print(text)
    

    【讨论】:

    • 问题的代码已经使用了显式编码。这有什么不同?
    • 这是 Python 中文件处理的一个很好的指针。与手头的问题没有直接关系,但很高兴知道。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-20
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多