Понимание Юникода и UTF-8

Доброе время суток участники образовательной IT площадки GeekSpace. Меня зовут Юрий Сиротенко и сегодня я расскажу о стандарте кодирования символов Юникод и о формате преобразования Юникода - UTF-8

Если вы хотите ознакомиться с данным материалом в видео формате, вы можете найти запись в лектории или просто перейти по ссылке. Также вы сможете получить методичку и перезентацию на данную тему под видео - лекцией.

Основная часть данного материала формировалась на основе одноименного видео “Characters, Symbols and the Unicode Miracle - Computerphile” на площадке youtube. В данном видео Том Скот рассказывает о чудесах юникода. Ссылку на видео и на твиттер аккаунт Скота вы можете найти в конце конспекта

Часть материала данной лекции была взята из интервью с Томом Скоттом и переведена на русский язык, а часть была сформирована на основе других статей, в частности из интернет энциклопедии Википедия. Желаю вам приятного чтения!

UTF-8 как чудо юникода

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

Оглядываясь в прошлое, а точнее в 1960 года у нас был телетайп - электромеханическая печатная машина, используемая для передачи между двумя абонентами текстовых сообщений по простейшему электрическому каналу (как правило это была пара проводов). Это было простое устройство которое позволяло нажимая на кнопки печатать сообщения. Каждой кнопки принадлежало число. Набор чисел отправляясь по каналу расшифровывался на стороне получателя, то есть по переданным числам производилось получение тех же символов, который вводил отправитель

Но появилась необходимость в стандартизации таких сообщений. В середине 1960-х годов в США был принят стандарт ASCII (American Standard Code for Information Interchange), что в переводе означает “Американский стандарт кода для обмена информацией”.

ASCII была семи битной двоичной системой. Каждый введенный символ конвертировался в семи битное бинарное число и отправлялся по сети. Это означает, что мы имеем числа от 0 до 127. Почему до 127? Все просто, ASCII является семи битной кодировкой, а при переводе десятичного числа 127 в двоичною систему исчисления получается “1111111”, то есть максимальное пороговое значение которое умещается в 7 разрядов.

Немного позднее были сделаны остальные символы. Были добавлены числа, знаки пунктуации и т.д. Разработчики стандарта поступили очень умно. К примеру заглавной букве “A” они присвоили число 65, что в двоичной системе исчисления соответствовало числу “1000001”. Далее символу “B” было присвоено число “66” которое при переводе в двоичную систему исчисления становилось “1000010”, символу “C” был присвоен номер “67” в двоичной “1000011” и т.д. Каждому специальному символу также был присущ свой набор чисел

Так и появился стандарт для, как минимум, англо говорящего мира. Для другой части мира были придуманы версии кодировки.

Время шло и появились 8-ми битные компьютеры. Вместе с ними появилась возможность кодирования при помощи не семи а восьми бит. Это означало что у восьми битных кодировок максимальное число в двоичной системе исчисления достигло “11111111”, что при переводе в десятичную систему исчисления доходило до числа 255, а это в два раза больше чем в семи битных кодировках. Данный прогресс означал, что теперь можно кодировать в два раза больше символов.

Множество стран начали вводить стандарты на свои национальные языки в рамках кодировки ASCII. Япония вообще не использовала кодировку ASCII, она создала свою собственную многобайтовую кодировку где на каждый символ приходилось несколько бинарных чисел.

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

Но это не было большой проблемой, потому что отправка документов кем - либо например из Лондона на абсолютно несовместимую машину, скажем, в Японии производилась очень редко. В те дни документы скорее печатались и отправлялись по факсу.

Проблема совместимости стала насущной в момент появления Всемирной паутины, когда документы начали рассылаться по всему миру. Все эти вещи стали предпосылкой к появлению организации “Консорциум Юникод”. Данная организация создала стандарт который вмещает более чем сто тысяч символов, что с избытком покрывало все, что вообще возможно написать на любом языке мира: английский алфавит, кириллические, арабские, японские, китайские, корейские символы и т.д.

Что мы имеет в итоге? Консорциум Юникода принял стандарт в котором более чем сто тысяч символов соответствовали более чем стам тысяч чисел. Консорциум в качестве кодирования не выбрал бинарные цифры, все, что он сделал это просто утвердил, что например, некому арабскому символу будет соответствовать некоторое десятичное число. Все стало гораздо проще и проблема совместимости была исчерпана.

Итак, у нас есть Юникод который представляет из себя стандарт кодирования символов, включающий в себя знаки почти всех письменных языков мира. Но числа, которые соответствуют символам, или проще говоря символы Юникода, нужно как то кодировать для более компактного хранения и передачи. Так и появился распространённый стандарт кодирования текста - UTF-8.

UTF-8 - распространённый восьми битный стандарт кодирования текста, позволяющий более компактно хранить и передавать символы Юникода, используя переменное количество байт (от 1 до 4), и обеспечивающий полную обратную совместимость с 7-битной кодировкой ASCII

Также стандарт кодирование “UTF-8” решил множество проблем, разъяснение которых выходит за рамки данного конспекта.

Алгоритм кодирования

Алгоритм кодирования в UTF-8 состоит из 3 этапов. Давайте рассмотрим каждый этап на примере реальных символов.

Этап 1

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

Возьмем символ “$”. В рамках юникода данному символу было присвоено десятичное число “36”. При переводе числа “36” в двоичную систему счисления получается семи разрядное число “100100”. Раз число 36 умещается в 8 бит (восемь, потому что utf-8 является восьми битной кодировкой), значит для кодирования числа нам хватит всего одного октета.

Этап 2

Второй этап подразумевает под собой установку старших битов первого октета в соответствии с необходимым количеством октетов, определенных на первом этапе. В случае с символом “$”, как мы уже убедились, это один октет.
В случае одного октета в качестве старшего бита нужно установить цифру “0”, чтобы число 36 уместилось ровно в 8 бит. В результате у нас получится восьми битный шаблон

0xxxxxxx

Этап 3

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

Как я говорил ранее, символу “$” в рамках юникода соответствует десятичное число “36”, которое при переводе в двоичную систему становится равным “100100”. Давайте наложим данное число на подготовленный в рамках второго этапа шаблон

00100100

Готово, символ “$” был успешно закодирован.

Теперь давайте рассмотрим символ, который занимает более чем 8 разрядов, например “€”. Данному символу в рамках юникода соответствует довольно крупное десятичное число - “8364”. Давайте пройдемся по всем трем этапам и закодируем данное число по стандарту UTF-8

Сначала определим, сколько октетов для кодирования нам необходимо. Переведем число “8364” в бинарный вид и получим четырнадцати разрядное число “10000010101100”.

Для определения необходимого количества UTF-8 байтов, можно обратиться к следующей таблице

Количество байт UTF-8

Количество бит

1

7

2

11

3

16

4

21

В числе “10000010101100” 14 битов, значит для кодирования в UTF-8 понадобится 3 октета.

Давайте подготовим шаблон для кодирования

1110xxxx 10xxxxxx 10xxxxxx

В первом октете мы указываем три однерки, что означает 3 октета и обязательный “0”. Во втором октете в первых двух битах указываем “10”, что означает “продолжение”. В третьем октете также как и во втором в первых двух битах мы указываем “10”, что также означает “продолжение”.

Для более удобного получения шаблонов по количеству байтов можно воспользоваться следующей шпаргалкой:

Количество октетов

Значащих бит

Шаблон

1

7

0xxxxxxx

2

11

110xxxxx 10xxxxxx

3

16

1110xxxx 10xxxxxx 10xxxxxx

4

21

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

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

11100010 10000010 10101100

Готово, символ “€” был успешно закодирован

Дополнительные материалы

Информация

Автор конспекта


Дата создания: 14.02.2019
Категория: Веб-разработка