【问题标题】:How does one ignore 4-byte utf-8 characters in Python?如何忽略 Python 中的 4 字节 utf-8 字符?
【发布时间】:2019-09-17 23:02:44
【问题描述】:

我正在尝试在 python 程序中进行网络抓取。我得到的 html 页面是 utf-8 格式。我在使用以下字符时遇到问题:'????' 我相信这是由于字符占用 4 个字节(编码为 b'\xf0\xa0\x86\xa2')。我还注意到Windows对utf-8不友好,我是Windows用户。

我试图找到一种方法来解析文本并删除错误的 4 字节字符,因为它出现了几个小时但没有成功。由于该字符是整行文本的一部分,因此我想解析该行并仅删除不可解码的字符。

def TryDecode(toParse):
    try:
        result = toParse.decode('utf-8', 'ignore') #No exception
    except UnicodeEncodeError:
        result = 'error'
    return result

badutf = b'  <li ...>\xf0\xa0\x86\xa2</li>\r\n'
res = TryDecode(badutf)
print("I see this")
print(res) # UnicodeEncodeError
print("I do not see this.")

预期结果:在 try 块中抛出错误或根本不抛出错误。 实际结果:直到第二个打印语句都没有错误。 注意:如果我包括 '????'我的脚本中的字符,也无法从 IDE 运行它。

编辑:感谢有用的建议,我现在明白了这个问题。如果其他人遇到类似问题,这是一个解决方案:

UCSTWOMAX = 65536 # Max value for UCS-2 formatting
def TryDecode(toParse):
    try:
        parsed = toParse.decode('utf-8', 'ignore')
        result = ''
        for c in parsed:
            if ord(c) < UCSTWOMAX:
                result += c
    except UnicodeEncodeError:
        result = 'error'
    return result

badutf = b'  <li ...>\xf0\xa0\x86\xa2</li>\r\n'
res = TryDecode(badutf)
print(res)
print("I see this now.")

【问题讨论】:

  • 您可能会发现例如/questions/6344853/python-unicode-in-windows-terminal-encoding-used 有用。

标签: python windows utf-8


【解决方案1】:

您的字节序列b'\xf0\xa0\x86\xa2' 解码为'\U000201a2'。这不是一个代码点,但它确实位于基本的多语言平面之外,这意味着许多软件(包括 Tk,以及使用 Tk 的 IDLE 等应用程序)将无法显示它。这是因为 Tk(尽管声称相反)并不完全支持 UTF-8,而只支持其前身标准 UCS-2(即 UTF-8,但没有 BMP 之外的字符)。

按照您的方式解码为 UTF-8:

res = TryDecode(badutf)

然后删除您的软件无法显示的字符:

fixed = res.replace('\U000201a2','')

附带说明,Windows 对 UTF-8 并非不友好。它是第一个支持 Unicode 的文件系统(大约 20 年前)。

【讨论】:

    【解决方案2】:

    我认为这篇文章可以解决您的问题: stackoverflow question 31805474 - encode error

    正如您所指出的,问题与 Windows 终端有关(如果您尝试在 jupyter 中运行代码,它将正确打印“?”而没有错误)。 您的 try 子句工作正常,因为它可以毫无问题地处理字符串; Traceback 是由 print() 本身 (...\lib\encodings\cp850.py) 生成的,它无法处理该字符。

    链接中的答案将避免 Traceback,但字符将通过一系列其他字符 (enter code here&lt;li ...&gt;𠆢&lt;/li&gt;) 呈现

    【讨论】:

    【解决方案3】:

    如果您在打印时遇到 UnicodeEncodeError,则您一定不能在 Windows 上使用 Python 3.6+。该版本及更高版本使用 Unicode 控制台 API。如果字体不支持字符,您可能会看到替换字符,但剪切和粘贴时打印的字符将在支持字符的应用程序中正确显示。

    例子:

    我在 Windows 终端中看到的内容:

    将相同的文本复制到 StackOverflow(Notepad/Notepad++ 也可以):

    Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> s = '\U000201a2'
    >>> print(s)
    ?
    

    如果只需要过滤BMP之外的字符,可以在解码字符串后使用:

    >>> s = "text\U000201a2more text"
    >>> s = ''.join(x for x in s if ord(x) < 65536)
    >>> s
    'textmore text'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-03
      • 2011-02-24
      • 2017-04-29
      • 2013-05-05
      • 2018-05-25
      • 2012-03-04
      相关资源
      最近更新 更多