gpt4 book ai didi

python - 重定向到文件时出现 UnicodeDecodeError

转载 作者:行者123 更新时间:2023-12-02 00:57:32 27 4
gpt4 key购买 nike

我在 Ubuntu 终端(编码设置为 utf-8)中运行此代码段两次,一次使用 ./test.py然后用 ./test.py >out.txt :

uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni

如果没有重定向,它会打印垃圾。通过重定向,我得到一个 UnicodeDecodeError。有人可以解释为什么我只在第二种情况下出现错误,或者甚至更好地详细解释两种情况下幕后发生的事情吗?

最佳答案

解决此类编码问题的关键在于理解原则上“字符串”的两个不同概念:(1)字符串,以及(2)字符串/字节数组。由于历史上普遍存在不超过 256 个字符的编码(ASCII、Latin-1、Windows-1252、Mac OS Roman 等),这种区别在很长一段时间内一直被忽略:这些编码将一组常见字符映射到0 到 255 之间的数字(即字节);在 Web 出现之前,相对有限的文件交换使得这种编码不兼容的情况是可以容忍的,因为大多数程序可以忽略存在多种编码的事实,只要它们生成的文本保留在同一操作系统上:这样的程序只会将文本视为字节(通过操作系统使用的编码)。正确的现代观点基于以下两点正确地将这两个字符串概念分开:

  • 字符大多与电脑无关:可以在黑板上画出来等等,比如بايثون、中蟒、🐍。机器的“字符”还包括“绘图指令”,例如空格、回车、设置书写方向的指令(阿拉伯语等)、重音等。very large character list包含在Unicode标准中;它涵盖了大多数已知字符。
  • 另一方面,计算机确实需要以某种方式表示抽象字符:为此,它们使用字节数组(包括 0 到 255 之间的数字),因为它们的内存以字节块的形式出现。将字符转换为字节的必要过程称为编码。因此,计算机需要编码才能表示字符。您计算机上的任何文本都经过编码(直到显示为止),无论是将其发送到终端(需要以特定方式编码的字符),还是保存在文件中。为了显示或正确“理解”(例如,通过 Python 解释器),字节流被解码为字符。 A few encodings(UTF-8、UTF-16……)是由 Unicode 为其字符列表定义的(因此 Unicode 定义了字符列表和这些字符的编码——仍有一些地方可以看到“Unicode 编码” "作为指代无处不在的 UTF-8 的一种方式,但这是不正确的术语,因为 Unicode 提供了多种编码)。

  • 综上所述, 计算机需要在内部用字节来表示字符,它们通过两个操作来实现:

    Encoding: characters → bytes

    Decoding: bytes → characters


    某些编码无法编码所有字符(例如 ASCII),而(某些)Unicode 编码允许您编码所有 Unicode 字符。编码也不一定是唯一的,因为某些字符可以直接表示或组合表示(例如基本字符和重音符号)。
    请注意 换行符 adds a layer of complication的概念,因为它可以由依赖于操作系统的不同(控制)字符表示(这就是Python的 universal newline file reading mode的原因)。

    如果您有兴趣,可以了解有关 Unicode、字符和代码点的更多信息:
    现在,我上面所说的“字符”就是Unicode所说的“ 用户感知字符”。单个用户感知的字符有时可以通过组合在 Unicode 列表中不同 indexes中找到的字符部分(基本字符、重音符号等)来表示,这些字符部分称为 code points“—这些代码点可以组合在一起形成一个“字素簇”。
    因此,Unicode 导致了字符串的第三个概念,由一系列 Unicode 代码点组成,位于字节和字符串之间,并且更接近后者。我将它们称为“ Unicode 字符串”(就像在 Python 2 中一样)。
    虽然 Python 可以打印(用户感知的)字符的字符串,但 Python 非字节字符串本质上是 Unicode 代码点的序列,而不是用户感知的字符。代码点值是在 Python 的 \u\UUnicode 字符串语法中使用的值。它们不应与字符的编码混淆(并且不必与它有任何关系:Unicode 代码点可以以各种方式进行编码)。
    这有一个重要的结果: Python (Unicode) 字符串的长度是它的代码点数,这并不总是它的用户感知字符数:因此 s = "\u1100\u1161\u11a8"; print(s, "len", len(s))(Python 3)给出 각 len 3,尽管 s具有单个用户感知(韩语)字符(因为它用 3 个代码点表示——即使它没有必要,如 print("\uac01")所示)。但是,在许多实际情况下,字符串的长度是用户感知的字符数,因为 Python 通常将许多字符存储为单个 Unicode 代码点。
    Python 2中,Unicode字符串被称为……“Unicode字符串”( unicode类型,字面形式 u"…"),而字节数组是“字符串”( str类型,其中字节数组例如可以用字符串文字 "…"构造)。在 Python 3中,Unicode字符串被简单地称为“字符串”( str类型,文字形式 "…"),而字节数组是“字节”( bytes类型,文字形式“679104”) .因此,像 b"…"这样的东西在 Python 2( "🐍"[0],一个字节)和 Python 3( '\xf0',第一个也是唯一的字符)中给出了不同的结果。
    有了这几个关键点,你应该能看懂大部分编码相关的问题了!

    通常,当你 打印 "🐍" 到终端时,你不应该得到垃圾:Python知道你终端的编码。实际上,您可以检查终端期望的编码:
    % python
    Python 2.7.6 (default, Nov 15 2013, 15:20:37)
    [GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import sys
    >>> print sys.stdout.encoding
    UTF-8
    如果您的输入字符可以用终端的编码进行编码,Python 会这样做,并将相应的字节发送到您的终端,而不会提示。终端将在解码输入字节后尽最大努力显示字符(最坏的情况是终端字体没有某些字符,而是打印某种空白)。
    如果您的输入字符无法使用终端的编码进行编码,则表示终端未配置为显示这些字符。 Python 会提示(在 Python 中带有 u"…",因为字符串无法以适合您终端的方式进行编码)。唯一可能的解决方案是使用可以显示字符的终端(通过配置终端使其接受可以表示您的字符的编码,或者使用不同的终端程序)。当您分发可在不同环境中使用的程序时,这一点很重要:您打印的消息应该可以在用户终端中表示。因此有时最好坚持只包含 ASCII 字符的字符串。
    然而,当你 重定向或管道输出你的程序时,通常是不可能知道接收程序的输入编码是什么,并且上面的代码返回一些默认编码:None(Python 2.7 ) 或 UTF-8 (Python 3):
    % python2.7 -c "import sys; print sys.stdout.encoding" | cat
    None
    % python3.4 -c "import sys; print(sys.stdout.encoding)" | cat
    UTF-8
    如果需要,stdin、stdout 和 stderr 的编码可以通过 UnicodeEncodeError环境变量为 set:
    % PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | cat
    UTF-8

    如果打印到终端没有产生您期望的结果,您可以检查您手动输入的 UTF-8 编码是否正确;例如,您的第一个字符( PYTHONIOENCODING)不可打印, if I'm not mistaken
    http://wiki.python.org/moin/PrintFails处,您可以找到类似以下的解决方案,适用于 Python 2.x:
    import codecs
    import locale
    import sys

    # Wrap sys.stdout into a StreamWriter to allow writing unicode.
    sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)

    uni = u"\u001A\u0BC3\u1451\U0001D10C"
    print uni
    对于 Python 3,您可以在 StackOverflow 上查看 one of the questions asked previously

    关于python - 重定向到文件时出现 UnicodeDecodeError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4545661/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com