Как игнорировать 4-байтовые символы utf-8 в Python? - PullRequest
0 голосов
/ 29 апреля 2019

Я пытаюсь поэкспериментировать с веб-скребком в программе на 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 ]

3 голосов
/ 29 апреля 2019

Ваша последовательность байтов b'\xf0\xa0\x86\xa2' декодируется до '\U000201a2'.Это не плохой код, но он лежит вне базовой многоязычной плоскости, что означает, что у многих программ (включая Tk и приложения типа IDLE, которые используют Tk) возникнут проблемы с его отображением.Это потому, что Tk (несмотря на утверждения об обратном) не полностью поддерживает UTF-8, а только его предшествующий стандарт UCS-2 (который является UTF-8, но без символов вне BMP).

Декодировать какUTF-8, как вы делаете:

res = TryDecode(badutf)

, затем удалите символ, который ваша программа имеет проблемы с отображением:

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

В качестве примечания, Windows не является недружественным для UTF-8,Это была первая файловая система, поддерживающая Unicode (около 20 лет назад).

1 голос
/ 29 апреля 2019

Если вы получаете UnicodeEncodeError при печати, вы не должны использовать Python 3.6+ в Windows.Эта версия и более поздние версии используют консольные API Unicode.Вы можете увидеть символ подстановки, если шрифт не поддерживает этот символ, но символы, напечатанные при вырезании и вставке, будут отображаться правильно в приложениях, которые поддерживают символы.

Пример:

ЧтоЯ вижу в терминале 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'
0 голосов
/ 29 апреля 2019

Я думаю, что этот пост может решить вашу проблему: stackoverflow вопрос 31805474 - ошибка кодирования

Как вы указали, проблема связана с терминалом Windows (если вы попытаетесь запустить свой код в jupyter, он будет правильно печатать '?' без ошибок). Ваше предложение try работает правильно, поскольку оно может обрабатывать строку без проблем; Traceback генерируется самой print () (... \ lib \ encodings \ cp850.py), которая не может обработать символ.

Ответ в ссылке позволит избежать трассировки, но персонаж будет отображаться через последовательность других символов (enter code here<li ...>𠆢</li>)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...