Руководство из Unicode на Python для начинающих

rukovodstvo iz unicode na python dlya nachinayushhih

Джимми Чжан

Однажды я провел пару неприятных дней на работе, обучаясь правильно работать со строчками Unicode в Python. За эти два дня я съел много закусок — примерно один мешок золотой рыбки на одну из этих ошибок, которые должны быть очень знакомы тем, кто программирует на Python:

UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xf0 in position 0: ordinal not in range(128)

Решая свою проблему, я много искал в Google, что указало мне на несколько незаменимых статей. Но как бы они ни были великолепны, все они были написаны без помощи важного аспекта общения в современном мире.

То есть: все они были написаны без помощи эмодзы.

Для того, чтобы воспользоваться этой ситуацией, я решил написать собственное руководство по пониманию Unicode с большим количеством лиц и значков, отображенных на пути «✌».

Прежде чем погрузиться в технические детали, начнём с интересного вопроса. Какой твой любимый смайлик?

Мое «лицо с открытым ртом», которое выглядит так? — с одной серьезной оговоркой. То, что вы видите, действительно зависит от платформы, которую вы используете для чтения этой публикации!

На моем Mac эмодзе выглядит как желтый шар для боулинга. На моем планшете Samsung глаза черные и круглые, подчеркнутые белой точкой, выдающей большую глубину эмоций.

Скопируйте и вставьте эмодзы (?) в Twitter, и вы увидите что-то совсем другое. Однако скопируйте и вставьте его на messenger.com, и вы поймете, почему он является моим любимым.

???? Почему все они разные?

xcqApm6uLo00aEV6quvQz5hbv0SMFnrxJwPc
xBNeNbexzlYavyagf0TqljD-3nGKVgBSqdtD
hj38DT5kCCXEAlXuor1E1JLjTtPBQtVKlaun
Слева направо: Apple, Samsung, messenger.com (источник).

Примечание. По состоянию на 9 июля 2018 г.: Мессенджер, похоже, обновил свои значки смайлов, поэтому значок в верхнем правом углу больше не применяется. ?

Эта веселая маленькая тайна – это наш путь в мир Unicode, поскольку смайлы являются частью стандарта Unicode с 2010 года. Кроме того, что Unicode дает нам смайлики, Unicode является важным, поскольку он является лучшим выбором Интернета для последовательного «кодирования, представления и обработки текста».

Юникод и кодирование: Краткое руководство

Как и со многими темами, лучший способ понять Unicode – это знать контекст его создания, а для этого обязательно нужно прочесть статью Джоэля Спольски.

Кодовые баллы

Поскольку мы сейчас вошли в мир Unicode, нам нужно сначала отделить эмодзы от удивительно выразительных значков, какие они есть, и ассоциировать их с чем-то гораздо менее увлекательным. Поэтому вместо того, чтобы думать о смайлах в терминах вещей или эмоций, которые они представляют, мы будем думать о каждом эмодзе как об обычном числе. Это число известно как а кодовая точка.

Кодовые точки являются ключевой концепцией Unicode, предназначенной для поддержания всемирного обмена, обработки и отображения письменных текстов на разных языках… современного мира». Он делает это, увязывая практически каждый печатный символ с уникальной кодовой точкой. Вместе эти символы составляют Unicode набор символов.

Кодовые точки, как правило, записываются в шестнадцатеричном формате с префиксом U+ для обозначения подключения к Unicode, представляющей символы из:

  • экзотические языки, такие как телугу [ఋ | code point: U+0C0B]
  • шахматные символы [♖ | code point: U+2656]
  • и, конечно, эмоди [? | code point: U+1F64C]

Глифы – это то, что вы видите

Фактическое представление на экране кодовых точек вызывается глифы( полное отображение кодовых точек к глифам известен как a шрифт).

Как пример, возьмите эту букву А, являющуюся кодовой точкой U+0041 в Unicode. Буква «А», которую вы видите воочию, является глифом – она выглядит так, как выглядит, потому что воспроизведена шрифтом Medium. Если бы вы изменили шрифт на, например, Times New Roman, изменился бы только глиф «А», а базовая кодовая точка – нет.

TUckLVh6eCihRLcdZhfa3l8qIE6IuxmCvLxY
Шрифты отображают ту же кодовую точку на разные глифы

Глифы – это ответ на нашу маленькую тайну визуализации. Под капотом все варианты лица с открытым ртом смайлики указывают на ту же кодовую точку, U+1F62Eно глиф что представляет его зависит от платформы?

Кодовые точки – это абстракции

Поскольку они ничего не говорят о том, как они отображаются зрительно (чтобы «оживить их», нужны шрифт и глиф), говорят, что кодовые точки являются абстракцией.

Но так же как кодовые точки являются абстракцией для конечных пользователей, они также являются абстракциями для компьютеров. Это потому, что кодовые точки требуют a кодировка символов чтобы превратить их в то, что компьютеры могут интерпретировать: байты. После преобразования в байты кодовые точки можно сохранить в файлы или отправить по сети на другой компьютер?➡️?.

UTF-8 на данный момент является самой популярной в мире кодировкой символов. UTF-8 использует набор правил для преобразования кодовой точки в уникальную последовательность (от 1 до 4) б, и напротив. Говорят, что кодовые точки есть закодированный на последовательность байтов, а последовательности байтов расшифровано в кодовые точки. Эта публикация о переполнении стека объясняет, как работает алгоритм кодирования UTF-8.

Однако, несмотря на то, что UTF-8 является преобладающей кодировкой символов в мире, она далеко не единственная. Например, UTF-16 является альтернативной кодировкой символов Unicode. На рисунке ниже сравниваются кодировки UTF-8 и UTF-16 наших смайлов.

k1TgNZ8m7zeByOT1BLyLSD8F7NBESOp7WLQO

Проблемы возникают, когда один компьютер кодирует кодовые точки в байты с одной кодировкой, а другой компьютер (или другой процесс на том же компьютере) декодирует эти байты с помощью другого.

К счастью, UTF-8 достаточно повсеместно, поэтому в большинстве случаев нам не придется беспокоиться о несоответствии кодировки символов. Но когда они случаются, нужно знакомство с понятиями, упомянутыми выше, чтобы выйти из передряги.

Краткий итог

  • Unicode – это коллекция кодовые точкикоторые являются обычными числами, обычно записываются в шестнадцатеричном формате с префиксом U+. Эти кодовые точки соответствуют практически каждому печатному символу из письменных языков всего мира.
  • Глифы является физическим проявлением характера. Этот парень? является глифом. А фont является отображением кодовых точек в глифе.
  • Чтобы отправить их по сети или сохранить в файле, символы и их базовые точки должны быть закодированы в байты. А кодировка символов содержит сведения о том, как кодовая точка встроена в последовательность байтов.
  • UTF-8 в настоящее время является обязательной популярностью в мире кодировка символов. Дана кодовая точка UTF-8 кодирует его в последовательность байтов. Задана последовательность байтов, UTF-8 декодирует его в кодовую точку.

Практический пример

Правильное воспроизведение символов Unicode включает в себя обход цепочки, начиная от байтов и кодовых точек до глифов.

4EWd0DC-ca2Xc-KykyfW7iVAHJhe6SjGG2Vx

Давайте теперь воспользуемся текстовым редактором, чтобы увидеть практический пример этой цепочки, а также типы проблем, которые могут возникнуть, когда что-то пошло не так. Текстовые редакторы идеальны, поскольку они включают в себя все три части цепочки визуализации, показанной выше.

Примечание. Следующий пример был сделан на моей MacOS с помощью Sublime Text 3. И чтобы отдать должное: начало этого примера очень вдохновлено этой публикацией Филиппа Го, которая познакомила меня с hexdump команда (и многое другое).

Мы начнем с текстового файла, содержащего один символ – мой любимый смайлик «лицо с открытым ртом». Для тех, кто хочет следить, я разместил этот файл в Github gist, который вы получаете локально с помощью curl.

curl  > emoji.txt

Как мы узнали, для того чтобы он был сохранен в файл, эмодзи был закодирован в байты с помощью кодировки символов. Этот конкретный файл был закодирован с помощью UTF-8 и мы можем использовать hexdump команда для проверки фактического содержимого байтов в файле.

j|encoding: hexdump emoji.txt0000000 f0 9f 98 ae 0000004

Выход из hexdump сообщает, что файл содержит 4 байта, каждый из которых записан в шестнадцатеричном формате. Фактическая последовательность байтов f0 9f 98 ae соответствует ожидаемой последовательности байтов, закодированной UTF-8, как показано ниже.

zRTpkcw12y2aFQOJyfTARuWgucf0CobcaKzf
Источник: http://www.ltg.ed.ac.uk/~richard/utf-8.cgi?input=%F0%9F%98%AE&mode=char

Теперь давайте откроем наш файл в Sublime Text, где мы должны увидеть наш сингл? характер. Поскольку мы видим ожидаемый глиф, мы можем предположить, что Sublime Text использовал правильную кодировку символов для декодирования этих байтов в кодовые точки. Подтвердим, открыв консоль View -> Show Console, и проверяя гоe viновый объект, который Sublime Text предоставляет как часть API Python.

>>> view<sublime.View object at 0x1112d7310>
# returns the encoding currently associated with the file>>> view.encoding()'UTF-8'

Имея немного знаний Python, мы также можем найти кодовую точку Unicode, связанную с нашим смайлом:

# Returns the character at the given position>>> view.substr(0)'?' 
# ord returns an integer representing the Unicode code point of the character (docs)>>> ord(view.substr(0))128558
# convert code point to hexadecimal, and format with U+>>> print('U+%x' % ord(view.substr(0)))U+1f62e

Снова так, как мы ожидали. Это иллюстрирует полный обход цепи визуализации Unicode, включающий:

  • чтение файла в качестве последовательности байтов, закодированных UTF-8.
  • декодирование байтов в кодовую точку Unicode
  • воспроизведение глифа, связанного с кодовой точкой.
tgfnKyW9kpVCBK4tkSwTiDncDR9-COPmFpw5
Фактический глиф, который вы видите зависит от платформы.

Все идет нормально?

Разные байты, тот же смайлик

Кроме того, что я мой любимый текстовый редактор, я выбрал Sublime Text для этого примера, поскольку он позволяет легко экспериментировать с кодировкой символов.

Теперь мы можем сохранить файл, используя другую кодировку символов. Для этого нажмите File -> Save with Encoding -> UTF-16 БЫТЬ. (Очень коротко, UTF-16 является альтернативной кодировкой символов Unicode. Вместо того, чтобы кодировать наиболее распространенные символы с помощью одного байта, как UTF-8, UTF-16 кодирует каждую точку от 1 до 65536 с помощью двух байтов. Кодовые точки больше 65536, как и наши эмодзы, кодируются с помощью суррогатных пар (BE означает Big Endian).

Когда мы используем hexdump чтобы повторно проверить файл, мы видим, что содержимое байтов изменилось.

# (before: UTF-8)j|encoding: hexdump emoji.txt0000000 f0 9f 98 ae 0000004
# (after: UTF-16 BE)j|encoding: hexdump emoji.txt0000000 d8 3d de 2e0000004

Вернувшись в Sublime Text, мы все еще видим то же самое? персонаж смотрит на нас. Сохранение файла с другой кодировкой символов могло изменить фактическое содержимое файла, но оно также обновило внутреннее представление Sublime Text о том, как интерпретировать эти байты. Мы можем подтвердить, снова запустив консоль.

>>> view.encoding()'UTF-16 BE'

С этого момента все остальное тоже самое.

>>> view.substr(0)'?' 
>>> ord(view.substr(0))128558
>>> print('U+%x' % ord(view.substr(0)))U+1f62e

Байты, возможно, изменились, но код не изменился — и смайлики остались неизменными.

Те же байты, но что за đŸ˜®

Время для «забавы» с кодировкой. Сначала давайте перекодируем наш файл с помощью UTF-8, поскольку это лучший пример.

Теперь давайте продолжим использовать Sublime Text, чтобы повторно открыть существующий файл, используя другую кодировку символов. под File -> Reopen with Encoding, click Vietnamese (Windows 1258), что превращает наш символ эмодзы в следующие четыре нелепых символа: đŸ˜®.

Когда мы нажимаем «Повторно открыть с помощью кодировки», мы не изменяем фактическое содержание байтов файла, а скорее способ интерпретации этих байтов Sublime Text. Hexdump подтверждает, что байты одинаковы:

j|encoding: hexdump emoji.txt0000000 f0 9f 98 ae0000004

Чтобы понять, почему мы видим эти нелепые символы, нам нужно обратиться к кодовой странице Windows-1258, которая является отображением байтов в набор символов вьетнамского языка. (Подумайте о кодовой странице как таблице, созданной кодировкой символов). Поскольку эта кодовая страница содержит набор символов менее 255 символов, кодовые точки каждого символа могут быть выражены в виде десятичного числа от 0 до 255, которое, в свою очередь, может быть закодировано с помощью 1 байта.

fvczjUIBIrUtsDTPr08NIdXLJqb9hjn6Hdd0
Кодовая страница Windows-1258, отображающая десятичные кодовые точки для символов вьетнамского языка. Взяты из Википедии, с некоторым пользовательским стилем, примененным для показа 4 кодовых точек, имеющих отношение к этому примеру.

Потому что наш холост? emoji требует 4 байта для кодирования с помощью UTF-8, теперь мы видим 4 символа, когда мы интерпретируем файл с кодировкой Windows-1258.

04v6iTqdJ7XiQfOMQxUtJMwto3JPS8gWcRZk

Неправильный выбор кодировки символов оказывает непосредственное влияние на то, что мы можем увидеть и понять, искажая символы в непонятном беспорядке.

lYN9Y31uDX5NwCb3ihQLoplb7e19gCepIxKf

Теперь к «веселой» части, которую я включаю, чтобы добавить немного цвета в Unicode и почему он существует. До Unicode существовало множество разных кодовых страниц, таких как Windows-1258, каждая из которых по-разному отображала 1 байт данных в 255 символов. Unicode был создан для того, чтобы объединить все разные символы всех разных кодовых страниц в одну систему. Другими словами, Unicode является сверхмножеством Windows-1258, и каждый символ на кодовой странице Windows-1258 имеет аналог Unicode.

PzRE5GqbSr6PLTSxNg2I3B5zeeRFfgVFCOBT
Коллеги Unicode для каждого символа указаны в средней строке каждой ячейки (Википедия)

Фактически, эти аналоги Unicode позволяют Sublime Text преобразовывать разные кодировки символов одним нажатием кнопки. Внутренне Sublime Text все еще представляет каждый из наших декодированных Windows-1258 символов как кодовую точку Unicode, как мы видим ниже, когда запускаем консоль:

>>> view.encoding()'Vietnamese (Windows 1258)'
# Python 3 strings are "immutable sequences of Unicode code points">>> type(view.substr(0))<class 'str'>
>>> view.substr(0)'đ'>>> view.substr(1)'Ÿ'>>> view.substr(2)'˜'>>> view.substr(3)'®'
>>> ['U+%04x' % ord(view.substr(x)) for x in range(0, 4)]['U+0111', 'U+0178', 'U+02dc', 'U+00ae']

Это означает, что мы можем повторно сохранить наши 4 нелепых символа с помощью UTF-8. Я оставлю это по вашему усмотрению — если вы это сделаете, и сможете правильно предсказать результат hexdump файла, то вы успешно поняли ключевые концепции Unicode, кодовые точки и кодировки символов. (Используйте эту кодовую страницу UTF-8. Ответ можно найти в самом конце этой статьи. ).

Подведению

Эффективная работа с Unicode предполагает всегда знать, на каком уровне цепи визуализации вы работаете. Это значит всегда спрашивать себя: что у меня есть? Под капотом глифы – это не что иное, как кодовые точки. Если вы работаете с кодовыми точками, знайте, что эти кодовые точки должны быть закодированы в байты с кодировкой символов. Если у вас есть последовательность байтов, представляющих текст, знайте, что эти байты не имеют смысла, не зная кодировки символов, которые были использованы для создания этих байтов.

Как и в любой теме информатики, лучший способ узнать Unicode — это экспериментировать. Вводите символы, играйте с кодировками символов и делайте предсказания, которые вы проверяете с помощью hexdump. Хотя я надеюсь, что эта статья объясняет все, что вам нужно знать о Unicode, я буду более чем рад, если она просто настроит вас на проведение собственных экспериментов.

Спасибо, что прочли! ?

ответ:

j|encoding: $ hexdump emoji.txt0000000 c4 91 c5 b8 cb 9c c2 ae0000008

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *