如何忽略Python中的4字节utf-8字符?

时间:2019-04-29 10:22:17

标签: python windows utf-8

我正在尝试在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.")

3 个答案:

答案 0 :(得分:3)

您的字节序列b'\xf0\xa0\x86\xa2'解码为'\U000201a2'。这不是 bad 的代码点,但它确实位于基本的多语言平台之外,这意味着许多软件(包括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年前)。

答案 1 :(得分:1)

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

示例:

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

enter image description here

将同一文本复制到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'

答案 2 :(得分:0)

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

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

链接中的答案将避免回溯,但是字符将通过一系列其他字符(enter code here<li ...>𠆢</li>)呈现