Почему кодировки в которых каждый символ
Перейти к содержимому

Почему кодировки в которых каждый символ

  • автор:

Почему современные компьютеры используют кодировки, в которых каждый символ занимает целое число

Однако сегодня, работая с сетевыми протоколами и сетевым программированием, вы столкнетесь с множеством схем кодирования данных и символов.

В этом руководстве мы рассмотрим основные схемы кодирования, используемые на компьютерах, а во второй части руководства мы рассмотрим, как данные передаются по сети.

Символы, целые числа, числа с плавающей точкой и т. д.

При хранении и передаче данных вам необходимо будет представлять следующие типы данных:

  • Символы и цифры, например A и 1
  • Длинные (32 бита) и короткие (16 бит) целые числа со знаком и без знака
  • Одинарное и двойное число с плавающей запятой
  • Логическое значение, т. е. True и False

Так как же компьютер запоминает букву А или цифру 1?

Как компьютер запоминает число вроде 60101? или 62.0101?

Как передать букву А и т. д. на другой компьютер по сети?

Компьютеры и кодировка символов

Чтобы сохранить текст в виде двоичных данных, необходимо указать кодировку для этого текста.

Компьютерные системы могут использовать различные схемы кодирования символов.

Пока данные остаются на компьютере, совершенно неважно, как они закодированы.

Однако для передачи данных между системами необходимо использовать стандартную схему кодирования.

В 1968 году ASCII (Американский стандартный код для обмена информацией) был принят в качестве стандарта кодирования текста для обмена данными.

ASCII

ASCII – это американский стандарт, разработанный для кодирования английских символов и знаков препинания, которые использовались на пишущих машинках и телетайпах того времени (1960-е годы).

ASCII использует 8 бит, хотя на самом деле используется только 7 бит.

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

В таблице ниже представлены сводные данные о распределении кодов.

Таблица ASCII – сводка кодов

Расширения ASCII

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

Эти расширения сохранили набор символов ASCII и использовали неиспользуемую часть адресного пространства и управляющие коды для дополнительных символов.

Наиболее распространенными являются Windows 1252 и Latin-1 (ISO-8859).

Windows 1252 и 7-битная кодировка ASCII были наиболее широко используемыми схемами кодирования до 2008 года, когда UTF-8 стал наиболее распространенным.

ISO-8859-1,ISO-8859-15, Latin-1

ISO-8859 — это 8-битная кодировка символов, которая расширяет 7-битную схему кодирования ASCII и используется для кодирования большинства европейских языков. Подробнее см. вики.

ISO-8859-1, также известный как Latin-1, является наиболее широко используемым, поскольку его можно использовать для большинства распространенных европейских языков, например немецкого, итальянского, испанского, французского и т. д.

Она очень похожа на схему кодирования Windows-1252, но не идентична, см. Сравнение символов в Windows-1252, ISO-8859-1, ISO-8859-15

Юникод

В связи с необходимостью кодирования символов иностранных языков и других графических символов был разработан набор символов Unicode и схемы кодирования.

Самые распространенные схемы кодирования:

UTF-8 – это наиболее часто используемая схема кодирования, используемая в современных компьютерных системах и компьютерных сетях.

Это схема кодирования переменной ширины, разработанная для полной обратной совместимости с ASCII. Он использует от 1 до 4 байт. – вики

Наборы символов и схемы кодирования

Разница между ними не всегда ясна, и термины, как правило, используются взаимозаменяемо.

Набор символов — это список символов, а схема кодирования — это то, как они представлены в двоичном формате.

Это лучше всего видно с Unicode.

Схемы кодирования UTF-8, UTF-16 и UTF-32 используют набор символов Unicode, но кодируют символы по-разному.

ASCII – это набор символов и схема кодирования.

Знак порядка байтов (BOM)

Знак порядка байтов (BOM) — это символ Unicode, U+FEFF, который появляется как магическое число в начале текстового потока и может сигнализировать программе, потребляющей текст, о нескольких вещах: –Wiki

  • Порядок байтов или порядок следования байтов в текстовом потоке;
  • Тот факт, что кодировка текстового потока — Unicode, с высокой степенью достоверности;
  • Какой Unicode кодирует текстовый поток.

Спецификация различается для текста в кодировке UTF-8, UTF-16 и UTF-32

Следующая таблица, взятая из Wiki, показывает это.

bom-table- пример

Спецификации и текстовые редакторы

Как правило, большинство редакторов правильно обрабатывают спецификацию, и она не отображается.

Программное обеспечение Microsoft, такое как Блокнот, добавляет спецификацию при сохранении данных в кодировке UTF-8 и не может интерпретировать текст без спецификации, если он не является чистым ASCII.

Пример спецификации

Ниже показан вывод простой программы на Python, которая отображает содержимое файла, содержащего символы TEST (4 символа), сохраненные в виде ASCII, UTF-8, UTF-16-BE и UTF-16-LE

BOM-example

Распространенные вопросы и ответы

В. Как узнать, какую кодировку символов использует файл?

A- Обычно это не так, но некоторые текстовые редакторы, такие как notepad++, отображают кодировку. Если вы получили файл, закодированный с помощью кодировки, отличной от ожидаемой, вы можете получить сообщение об ошибке при попытке его чтения.

В. Мой файл в формате ASCII, но он нормально декодируется с помощью декодера UTF-8. Почему?

A- Потому что UTF-8 обратно совместим с ASCII.

Целые числа и числа с плавающей запятой — Big и Little Endian

Примечание. Поскольку в кодировках UTF-16 и UTF-32 используются 2-байтовые или 4-байтовые целые числа, к кодированию текста с их использованием применяется следующее

Количество байтов, выделенных для целого числа или числа с плавающей запятой, зависит от системы.

Пункт Tutorials описывает это для языка программирования C, и я буду использовать его для иллюстрации

Если мы возьмем короткое целое как 2 байта, а длинное целое как 4 байта.

Поскольку они используют несколько байтов, возникает несколько вопросов:

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

Окончание байтов относится к последовательному порядку, в котором байты упорядочиваются в более крупные числовые значения при сохранении в памяти или при передаче по цифровым каналам связи.
Окончание байтов представляет интерес в информатике, потому что два конфликтующих и несовместимых формата широко используются: слова могут быть представлены в формате с прямым порядком байтов или прямым порядком байтов, в зависимости от того, упорядочены ли биты, байты или другие компоненты от большого конец (самый значащий бит) или маленький конец (наименьший значащий бит).
В формате с обратным порядком байтов при адресации памяти или отправке/сохранении слов побайтно сохраняется старший значащий байт — байт, содержащий старший значащий бит. первый (имеет младший адрес) или отправляется первым, затем следующие байты сохраняются или отправляются в порядке убывания значимости, причем младший байт — тот, который содержит младший значащий бит — сохраняется последним (имеет самый высокий адрес) или отправляется последним.

Вики

int- Пример кодирования байтов

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

Сетевой порядок байтов и системный порядок байтов

Сетевой порядок байтов – это порядок расположения байтов при отправке данных по сети. ( TCP/IP обычно имеет формат Big Endian ).

Это означает, что старший байт отправляется первым.

Системный порядок байтов или порядок байтов хоста — это способ размещения байтов при сохранении в памяти хост-системы.

Понимание Unicode и кодировок символов

Введение: весь открытый текст представлен в виде байтов (целых чисел)

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

Большая часть данных, с которыми мы работаем, хранится в файлах с открытым текстом, которые представляют собой просто потоки символов. Типы файлов с открытым текстом включают .txt, .csv, .json, .html и .xml . Однако в наших компьютерных системах все файлы хранятся в двоичном виде. Файлы с открытым текстом хранятся в виде целых чисел, где каждое целое число (иногда 2–4 целых числа) представляет символ.

Каждое целое число занимает в нашей системе байт, поэтому строки целых чисел, представляющие символы, называются байтовыми строками. Чтобы просмотреть текст в приложении (например, в текстовом редакторе, браузере, Python и т. д.), целые числа в строке байтов должны быть преобразованы в символы. Для этого приложение должно ссылаться на кодировку, указывающую целочисленное значение, соответствующее каждому символу в наборе символов. Каждый раз, когда мы смотрим на текст, будь то в редакторе, IDE, браузере или программе Python, строки байтов преобразуются в текст. Это происходит незаметно и плавно (хотя иногда вы можете увидеть знак ? в чате или на веб-странице — это означает, что конвертер не знал, как преобразовать это целое число).

Таблица ASCII: исходный набор символов

Исходный набор символов, впервые использованный на компьютерах, известен как таблица ascii. Если вы посмотрите на эту таблицу и выберете целые эквиваленты для «привет, мир!» вы увидите, что они совпадают с предыдущими привет, мир! пример.

Вы также можете увидеть аналогичный перевод в действии, используя функции ord() и chr():

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

Юникод: попытка создать универсальный набор символов

Существует много наборов символов; UTF-8 – наиболее распространенная кодировка Unicode.

Юникод в Python: кодирование и декодирование строк байтов

Строка – это последовательность символов; строка байтов — это последовательность целых чисел, представляющих каждый символ, отображаемый посредством кодировки .

Как мы уже говорили, весь текст хранится в виде целочисленных значений, каждое целое число представляет символ. При отображении текста целые числа должны быть преобразованы в символы. Это означает, что каждый раз, когда вы видите символы, представленные в файле — в редакторе, браузере или программе Python — эти символы были декодированы из целочисленных значений. Чтобы декодировать целое число в соответствующий символ, приложение должно обратиться к кодировке, которая отображает целочисленные значения в символы. ascii — одна из таких кодировок, utf-8 — другая. Это означает, что каждое строковое представление текста, которое вы видите, было декодировано из целых чисел с использованием кодировки.

Чтобы Python кодировал строку в целочисленную строку байтов, мы используем метод str.encode():

Строка байтов обозначается буквой b» . Он печатает со строковыми символами, потому что Python по умолчанию применяет кодировку utf-8.

Чтобы декодировать строку байтов в строку, мы используем метод bytes.decode(), предоставляющий кодировку:

Большинство современных приложений, таких как Python, по умолчанию используют utf-8. Если мы хотим открыть файл с другой кодировкой, мы можем указать это в open() :

Мы также можем открыть файл для чтения как байты с аргументом rb:

И мы также можем записывать необработанные байты в файл:

Обработка ошибок декодирования и кодирования

Мы можем перехватывать ошибки декодирования и кодирования и/или удалять или заменять недопустимые символы.

Строки и строки байтов не содержат информации о кодировке; это означает, что даже они не «знают», какую кодировку они используют, и поэтому не могут сказать нам, какую кодировку использовать.

Итак, мы можем получить текст, который неправильно кодируем или декодируем:

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

Если мы обнаружим, что строка не может быть декодирована в указанную кодировку, мы можем либо удалить, либо заменить неизвестный символ:

‘replace’ создает только буквальный вопросительный знак для замены неизвестного символа; «игнорировать» удаляет его «прослушивание» кодировки строки байтов. Строка байтов не содержит метаинформации, поэтому она «не знает», какая кодировка использовалась для ее создания.

Python предоставляет модуль chardet, который может проверять строку байтов, чтобы определить ее кодировку. Мы называем этот вид доказательной экспертизы «обнюхиванием»:

Вероятно, вы знаете, что все на компьютере хранится в виде строк битов (двоичных цифр; вы можете думать о них как о множестве маленьких переключателей). Здесь мы объясним, как эти биты используются для представления букв и цифр, которые обрабатывает ваш компьютер.

Прежде чем мы приступим к этому, вам нужно понять размер слова вашего компьютера. Размер слова является предпочтительным размером компьютера для перемещения единиц информации; технически это ширина регистров вашего процессора, которые являются областями хранения, которые ваш процессор использует для выполнения арифметических и логических вычислений. Когда люди пишут о компьютерах с разрядностью (называя их, скажем, «32-битными» или «64-битными»), они имеют в виду именно это.

Большинство компьютеров теперь имеют размер слова 64 бита. В недавнем прошлом (начало 2000-х) многие ПК имели 32-битные слова. Старые машины 286 в 1980-х годах имели размер слова 16. В старых мейнфреймах часто использовались 36-битные слова.

Компьютер рассматривает вашу память как последовательность слов, пронумерованных от нуля до некоторого большого значения, зависящего от объема вашей памяти. Это значение ограничено размером вашего слова, поэтому программы на старых машинах, таких как 286, должны были пройти через болезненные искажения, чтобы адресовать большие объемы памяти. Я не буду описывать их здесь; они до сих пор вызывают кошмары у программистов постарше.

Целые числа представлены в виде слов или пар слов, в зависимости от размера слова вашего процессора. Одно 64-битное машинное слово является наиболее распространенным целочисленным представлением.

Целая арифметика близка к математической системе счисления по основанию два, но не совсем ей. Младший бит равен 1, затем 2, затем 4 и так далее, как в чистом двоичном коде. Но числа со знаком представлены в записи с дополнением до двух. Бит старшего разряда — это бит знака, который делает величину отрицательной, и каждое отрицательное число может быть получено из соответствующего положительного значения путем инвертирования всех битов и добавления единицы. Вот почему целые числа на 64-битной машине имеют диапазон от -2 63 до 2 63 — 1.Этот 64-й бит используется для знака; 0 означает положительное число или ноль, 1 — отрицательное число.

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

Большинство процессоров и некоторые языки могут выполнять операции с числами с плавающей запятой (эта возможность встроена во все современные чипы процессоров). Числа с плавающей запятой дают гораздо более широкий диапазон значений, чем целые числа, и позволяют выражать дроби. Способы, которыми это делается, различны и слишком сложны, чтобы подробно обсуждать их здесь, но общая идея очень похожа на так называемую «научную нотацию», где можно записать, скажем, 1,234 * 10 23 ; кодирование числа разделено на мантисса (1,234) и экспоненциальную часть (23) для множителя степени десяти (что означает, что умноженное число будет иметь 20 нулей, 23 минус три десятичных знака).

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

Главная из них заключается в том, что не во всем мире используется ASCII. На самом деле, большая часть мира не может — ASCII, хотя и подходит для американского английского, не имеет многих акцентированных и других специальных символов, необходимых пользователям других языков. Даже в британском английском есть проблемы с отсутствием знака фунта стерлингов.

Было несколько попыток решить эту проблему. Все они используют дополнительный старший бит, которого нет в ASCII, что делает его младшей половиной набора из 256 символов. Наиболее широко используемым из них является так называемый набор символов «Latin-1» (более формально называемый ISO 8859-1). Это набор символов по умолчанию для Linux, старых версий HTML и X. Microsoft Windows использует измененную версию Latin-1, которая добавляет набор символов, таких как правые и левые двойные кавычки, в тех местах, где правильный Latin-1 оставляет неназначенными для исторических данных. причинам (обзорный отчет о проблемах, которые это вызывает, см. на странице деморонизатора).

Latin-1 поддерживает западноевропейские языки, включая английский, французский, немецкий, испанский, итальянский, голландский, норвежский, шведский, датский и исландский. Однако этого тоже недостаточно, и в результате существует целая серия наборов символов от латиницы от 2 до -9 для обработки таких вещей, как греческий, арабский, иврит, эсперанто и сербско-хорватский. Подробности см. на странице супа с алфавитом ISO.

Наилучшее решение — огромный стандарт Unicode (и его аналог ISO/IEC 10646-1:1993). Unicode идентичен Latin-1 в самых нижних 256 слотах. Над ними в 16-битном пространстве он включает греческий, кириллический, армянский, иврит, арабский, деванагари, бенгальский, гурмукхи, гуджарати, ория, тамильский, телугу, каннада, малаялам, тайский, лаосский, грузинский, тибетский, японский Кана, полный набор современных корейских хангыль и единый набор китайских/японских/корейских (CJK) иероглифов. Дополнительные сведения см. на домашней странице Unicode. XML и XHTML используют этот набор символов.

Понимание Unicode и кодировок символов

Введение: весь открытый текст представлен в виде байтов (целых чисел)

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

Большая часть данных, с которыми мы работаем, хранится в файлах с открытым текстом, которые представляют собой просто потоки символов. Типы файлов с открытым текстом включают .txt, .csv, .json, .html и .xml . Однако в наших компьютерных системах все файлы хранятся в двоичном виде. Файлы с открытым текстом хранятся в виде целых чисел, где каждое целое число (иногда 2–4 целых числа) представляет символ.

Каждое целое число занимает в нашей системе байт, поэтому строки целых чисел, представляющие символы, называются байтовыми строками. Чтобы просмотреть текст в приложении (например, в текстовом редакторе, браузере, Python и т. д.), целые числа в строке байтов должны быть преобразованы в символы. Для этого приложение должно ссылаться на кодировку, указывающую целочисленное значение, соответствующее каждому символу в наборе символов. Каждый раз, когда мы смотрим на текст, будь то в редакторе, IDE, браузере или программе Python, строки байтов преобразуются в текст. Это происходит незаметно и плавно (хотя иногда вы можете увидеть знак ? в чате или на веб-странице — это означает, что конвертер не знал, как преобразовать это целое число).

Таблица ASCII: исходный набор символов

Исходный набор символов, впервые использованный на компьютерах, известен как таблица ascii. Если вы посмотрите на эту таблицу и выберете целые эквиваленты для «привет, мир!» вы увидите, что они совпадают с предыдущими привет, мир! пример.

Вы также можете увидеть аналогичный перевод в действии, используя функции ord() и chr():

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

Юникод: попытка создать универсальный набор символов

Существует много наборов символов; UTF-8 – наиболее распространенная кодировка Unicode.

Юникод в Python: кодирование и декодирование строк байтов

Строка – это последовательность символов; строка байтов — это последовательность целых чисел, представляющих каждый символ, отображаемый посредством кодировки .

Как мы уже говорили, весь текст хранится в виде целочисленных значений, каждое целое число представляет символ. При отображении текста целые числа должны быть преобразованы в символы. Это означает, что каждый раз, когда вы видите символы, представленные в файле — в редакторе, браузере или программе Python — эти символы были декодированы из целочисленных значений. Чтобы декодировать целое число в соответствующий символ, приложение должно обратиться к кодировке, которая отображает целочисленные значения в символы. ascii — одна из таких кодировок, utf-8 — другая. Это означает, что каждое строковое представление текста, которое вы видите, было декодировано из целых чисел с использованием кодировки.

Чтобы Python кодировал строку в целочисленную строку байтов, мы используем метод str.encode():

Строка байтов обозначается буквой b» . Он печатает со строковыми символами, потому что Python по умолчанию применяет кодировку utf-8.

Чтобы декодировать строку байтов в строку, мы используем метод bytes.decode(), предоставляющий кодировку:

Большинство современных приложений, таких как Python, по умолчанию используют utf-8. Если мы хотим открыть файл с другой кодировкой, мы можем указать это в open() :

Мы также можем открыть файл для чтения как байты с аргументом rb:

И мы также можем записывать необработанные байты в файл:

Обработка ошибок декодирования и кодирования

Мы можем перехватывать ошибки декодирования и кодирования и/или удалять или заменять недопустимые символы.

Строки и строки байтов не содержат информации о кодировке; это означает, что даже они не «знают», какую кодировку они используют, и поэтому не могут сказать нам, какую кодировку использовать.

Итак, мы можем получить текст, который неправильно кодируем или декодируем:

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

Если мы обнаружим, что строка не может быть декодирована в указанную кодировку, мы можем либо удалить, либо заменить неизвестный символ:

‘replace’ создает только буквальный вопросительный знак для замены неизвестного символа; «игнорировать» удаляет его «прослушивание» кодировки строки байтов. Строка байтов не содержит метаинформации, поэтому она «не знает», какая кодировка использовалась для ее создания.

Python предоставляет модуль chardet, который может проверять строку байтов, чтобы определить ее кодировку. Мы называем этот вид доказательной экспертизы «обнюхиванием»:

Вероятно, вы знаете, что все на компьютере хранится в виде строк битов (двоичных цифр; вы можете думать о них как о множестве маленьких переключателей). Здесь мы объясним, как эти биты используются для представления букв и цифр, которые обрабатывает ваш компьютер.

Прежде чем мы приступим к этому, вам нужно понять размер слова вашего компьютера. Размер слова является предпочтительным размером компьютера для перемещения единиц информации; технически это ширина регистров вашего процессора, которые являются областями хранения, которые ваш процессор использует для выполнения арифметических и логических вычислений. Когда люди пишут о компьютерах с разрядностью (называя их, скажем, «32-битными» или «64-битными»), они имеют в виду именно это.

Большинство компьютеров теперь имеют размер слова 64 бита. В недавнем прошлом (начало 2000-х) многие ПК имели 32-битные слова. Старые машины 286 в 1980-х годах имели размер слова 16. В старых мейнфреймах часто использовались 36-битные слова.

Компьютер рассматривает вашу память как последовательность слов, пронумерованных от нуля до некоторого большого значения, зависящего от объема вашей памяти. Это значение ограничено размером вашего слова, поэтому программы на старых машинах, таких как 286, должны были пройти через болезненные искажения, чтобы адресовать большие объемы памяти. Я не буду описывать их здесь; они до сих пор вызывают кошмары у программистов постарше.

Целые числа представлены в виде слов или пар слов, в зависимости от размера слова вашего процессора. Одно 64-битное машинное слово является наиболее распространенным целочисленным представлением.

Целая арифметика близка к математической системе счисления по основанию два, но не совсем ей. Младший бит равен 1, затем 2, затем 4 и так далее, как в чистом двоичном коде. Но числа со знаком представлены в записи с дополнением до двух. Бит старшего разряда — это бит знака, который делает величину отрицательной, и каждое отрицательное число может быть получено из соответствующего положительного значения путем инвертирования всех битов и добавления единицы. Вот почему целые числа на 64-битной машине имеют диапазон от -2 63 до 2 63 — 1. Этот 64-й бит используется для знака; 0 означает положительное число или ноль, 1 — отрицательное число.

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

Большинство процессоров и некоторые языки могут выполнять операции с числами с плавающей запятой (эта возможность встроена во все современные чипы процессоров). Числа с плавающей запятой дают гораздо более широкий диапазон значений, чем целые числа, и позволяют выражать дроби. Способы, которыми это делается, различны и слишком сложны, чтобы подробно обсуждать их здесь, но общая идея очень похожа на так называемую «научную нотацию», где можно записать, скажем, 1,234 * 10 23 ; кодирование числа разделено на мантисса (1,234) и экспоненциальную часть (23) для множителя степени десяти (что означает, что умноженное число будет иметь 20 нулей, 23 минус три десятичных знака).

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

Главная из них заключается в том, что не во всем мире используется ASCII. На самом деле, большая часть мира не может — ASCII, хотя и подходит для американского английского, не имеет многих акцентированных и других специальных символов, необходимых пользователям других языков. Даже в британском английском есть проблемы с отсутствием знака фунта стерлингов.

Было несколько попыток решить эту проблему. Все они используют дополнительный старший бит, которого нет в ASCII, что делает его младшей половиной набора из 256 символов. Наиболее широко используемым из них является так называемый набор символов «Latin-1» (более формально называемый ISO 8859-1). Это набор символов по умолчанию для Linux, старых версий HTML и X. Microsoft Windows использует измененную версию Latin-1, которая добавляет набор символов, таких как правые и левые двойные кавычки, в тех местах, где правильный Latin-1 оставляет неназначенными для исторических данных. причинам (обзорный отчет о проблемах, которые это вызывает, см. на странице деморонизатора).

Latin-1 поддерживает западноевропейские языки, включая английский, французский, немецкий, испанский, итальянский, голландский, норвежский, шведский, датский и исландский. Однако этого тоже недостаточно, и в результате существует целая серия наборов символов от латиницы от 2 до -9 для обработки таких вещей, как греческий, арабский, иврит, эсперанто и сербско-хорватский. Подробности см. на странице супа с алфавитом ISO.

Наилучшее решение — огромный стандарт Unicode (и его аналог ISO/IEC 10646-1:1993). Unicode идентичен Latin-1 в самых нижних 256 слотах. Над ними в 16-битном пространстве он включает греческий, кириллический, армянский, иврит, арабский, деванагари, бенгальский, гурмукхи, гуджарати, ория, тамильский, телугу, каннада, малаялам, тайский, лаосский, грузинский, тибетский, японский Кана, полный набор современных корейских хангыль и единый набор китайских/японских/корейских (CJK) иероглифов. Дополнительные сведения см. на домашней странице Unicode. XML и XHTML используют этот набор символов.

Читайте также:

  • Как перенести файлы с телефона на телефон
  • Pci x что это такое
  • Qbittorrent или utorrent, что лучше
  • Много коротких сигналов при включении компьютера
  • Бортовой компьютер на Aveo вместо часов на Aveo

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

В современных компьютерах широко используются кодировки, в которых каждый символ занимает целое число байтов, по нескольким причинам:

  1. Эффективность использования памяти: Целочисленное количество байтов для каждого символа позволяет оптимизировать использование памяти. Компьютеры работают на основе двоичной системы, где память обычно адресуется блоками байтов. Если символ занимает фиксированное количество байтов, это упрощает расчет адресов и управление памятью.
  2. Простота обработки и доступа к символам: Когда каждый символ занимает фиксированное количество байтов, обработка и доступ к символам становятся более простыми и эффективными. Компьютеры могут легко перемещаться по памяти на основе фиксированного размера символов, что упрощает операции чтения, записи и обработки текстовых данных.
  3. Совместимость с аппаратными устройствами: Многие аппаратные устройства, такие как процессоры, память и периферийные устройства, разработаны с учетом целочисленного размера символов. Использование кодировок, где каждый символ занимает целое число байтов, позволяет легко интегрировать текстовые данные с аппаратными компонентами компьютера.
  4. Скорость обработки: Обработка текстовых данных, когда каждый символ занимает фиксированное количество байтов, может быть более быстрой и эффективной. Это связано с простотой алгоритмов обработки и оптимизацией работы с памятью и процессором.

Однако следует отметить, что размер символа, занимаемого кодировкой, может варьироваться в разных системах и кодировках. Например, в UNICODE символы могут занимать разное количество байтов в зависимости от используемого формата кодировки (UTF-8, UTF-16, UTF-32). Также стоит учитывать, что использование фиксированного размера символов имеет свои ограничения и может потребовать дополнительных механизмов для поддержки более широкого спектра символов и письменностей.

Что такое кодировки

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

Сейчас Unicode — это основной стандарт кодирования символов, включающий в себя знаки почти всех письменных языков мира. Unicode применяется везде, где есть текст. Информация на страницах в социальных сетях, записи в базах данных, компьютерные программы и мобильные приложения — всё это работает с использованием Unicode.

В этом гайде мы рассмотрим, как появился Unicode и какие проблемы он решает. Узнаем, как хранилась и передавалась информация до введения единого стандарта кодирования символов, а также рассмотрим примеры кодировок, основанных на Unicode.

Предпосылки появления кодировок

Исторически компьютер создавался как машина для ускорения и автоматизации вычислений. Само слово computer с английского можно перевести как вычислитель, а в 20 веке в СССР, до распространения термина компьютер, использовалась аббревиатура ЭВМ — электронно вычислительная машина.

Всё, чем компьютеры оперировали — числа. Основным заказчиком и драйвером появления первых моделей были оборонные предприятия. На компьютерах проводили расчёты параметров полёта баллистических ракет, самолётов, спутников. В 1950-е годы вычислительные мощности компьютеров стали использовать для:

  • прогноза погоды;
  • вычислений экспериментальной и теоретической физики;
  • расчета заработной платы сотрудников (например, компьютер LEO применялся для нужд компании, владеющей сетью чайных магазинов);
  • прогнозирование результатов выборов президента США (1952 год, компьютер UNIVAC).

Компьютеры и числа

Цели, для которых разрабатывались компьютеры, привели к появлению архитектуры, предназначенной для работы с числами. Они хранятся в компьютере следующим образом:

  1. Число из десятичной системы счисления переводится в двоичную, т.е. набор нулей и единиц. Например, 3 в двоичной системе счисления можно записать в виде 11, а 9 как 1001. Подробнее о системах счисления читайте в соответствующем гайде.
  2. Полученный набор нулей и единиц хранится в ячейках памяти компьютера. Например, наличие тока на элементе памяти означает единицу, его отсутствие — ноль.

картинка о записи чисел в память

В конце 1950-х годов происходит замена ламп накаливания на полупроводниковые элементы (транзисторы и диоды). Внедрение новой технологии позволило уменьшить размеры компьютеров, увеличить скорость работы и надёжность вычислений, а также повлияло на конечную стоимость. Если первые компьютеры были дорогостоящими штучными проектами, которые могли себе позволить только государства или крупные компании, то с применением полупроводников начали появляться серийные компьютеры, пусть даже и не персональные.

Компьютеры и символы

Постепенно компьютеры начинают применяться для решения не только вычислительных или математических задач. Возникает необходимость обработки текстовой информации, но с буквами и другими символами ситуация обстоит сложнее, чем с числами. Символы — это визуальный объект. Даже одна и та же буква «а» может быть представлена двумя различными символами «а» и «А» в зависимости от регистра.

Также число «один» можно представить в виде различных символов. Это может быть арабская цифра 1 или римская цифра I. Значение числа не меняется, но символы используются разные.

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

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

Картинка о записи символов в память

Распространение компьютеров

В начале 1960-х годов компьютеры были несовместимы друг с другом даже в рамках одной компании-производителя. Например, в компании IBM насчитывалось около 20 конструкторских бюро, и каждое разрабатывало свою собственную модель. Такие компьютеры не были универсальными, они создавались для решения конкретных задач. Для каждой решаемой задачи формировалась необходимая таблица символов, и проектировались устройства ввода/вывода информации.

В этот период начинают формироваться сети, соединяющие в себе несколько компьютеров. Так, в 1958 году создали систему SAGE (Semi-Automatic Ground Environment), объединившую радарные станций США и Канады в первую крупномасштабную компьютерную сеть. При этом, чтобы результаты вычислений одних компьютеров можно было использовать на других компьютерах сети, они должны были обладать одинаковыми таблицами символов.

В 1962 году компания IBM формирует два главных принципа для развития собственной линейки компьютеров:

  1. Компьютеры должны стать универсальными. Это означало переход от производства узкоспециализированных компьютеров к машинам, которые могут решать разные задачи.
  2. Компьютеры должны стать совместимыми друг с другом, то есть должна быть возможность использовать данные с одного компьютера на другом.

Так в 1965 году появились компьютеры IBM System/360. Это была линейка из шести моделей, состоящих из совместимых модулей. Модели различались по производительности и стоимости, что позволило заказчикам гибко подходить к выбору компьютера. Модульность систем привела к появлению новой отрасли — производству совместимых с System/360 вычислительных модулей. У компаний не было необходимости производить компьютер целиком, они могли выходить на рынок с отдельными совместимыми модулями. Всё это привело к ещё большему распространению компьютеров.

ASCII как первый стандарт кодирования информации

Телетайп и терминал

Параллельно с этим развивались телетайпы. Телетайп — это система передачи текстовой информации на расстоянии. Два принтера и две клавиатуры (на самом деле электромеханические печатные машинки) попарно соединялись друг с другом проводами. Текст, набранный на клавиатуре у первого пользователя, печатается на принтере у второго пользователя и наоборот. Таким образом, например, была организована «горячая линия» между президентом США и руководством СССР вплоть до начала 1970-х годов.

Телетайпы также преобразуют текстовую информацию в некоторые сигналы, которые передаются по проводам. При этом не всегда используется бинарный код, например, в азбуке Морзе используются 3 символа — точка, тире и пауза. Для телетайпов необходимы таблицы символов, соответствие в которых строится между символами и сигналами в проводах. При этом для каждого телетайпа (пары, соединённых телетайпов) таблицы символов могли быть свои, исходя из задач, которые они решали. Отличаться, например, мог язык, а значит и сам набор символов, который отправлялся с помощью устройства. Для оптимизации работы телетайпа самые популярные (часто встречающиеся) символы кодировались наиболее коротким набором сигналов, а значит и в рамках одного языка, набор символов мог быть разным.

На основе телетайпов разработали терминалы доступа к компьютерам. Такой телетайп отправлял сообщения не второму пользователю, а информация вводилась на некоторый удалённый компьютер, который после обработки указанных команд, возвращал результат в виде ответного сообщения. Это нововведение позволило использовать тогда ещё очень дорогие вычислительные мощности компьютеров, не имея физического доступа к самому компьютеру. Например, компьютер мог размещаться в отдельном вычислительном центре корпорации или института, а сотрудники из других филиалов или городов получали доступ к вычислительным мощностями компьютера посредством установленных у них терминалов.

ASCII

Повсеместное распространение компьютеров и средств обмена текстовой информацией потребовало разработки единого стандарта кодирования для передачи и хранения информации. Такой стандарт разработали в США в 1963 году. Таблицу из 128 символов назвали ASCII — American standard code for information interchange (Американский стандарт кодов для обмена информацией).

ASCII image

Первые 32 символа в ASCII являются управляющими. Они использовались для того, чтобы, например, управлять печатающим устройством телетайпа и получать некоторые составные символы. Например:

  1. символ Ø можно было получить так: печатаем O, затем с помощью управляющего кода BS (BackSpace) передвигаем печатную головку на один символ назад и печатаем символ /,
  2. символ à получался как a BS `
  3. символ Ç получался как C BS ,

Введение управляющих символов позволяло получать новые символы как комбинацию существующих, не вводя дополнительные таблицы символов.

Однако введение стандарта ASCII решило вопрос только в англоговорящих странах. В странах с другой письменностью, например, с кириллической в СССР, проблема оставалась.

Переход к Unicode

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

В результате в октябре 1991 года появилась первая версия одной общей таблицы символов, названной Unicode. Она включала в себя на тот момент 7161 различный символ из 24 письменностей мира.

В Unicode постепенно добавлялись новые языки и символы. Например, в версию 1.0.1 в середине 1992 года добавили более 20 000 идеограмм китайского, японского и корейского языков. В актуальной на текущий момент версии содержится уже более 143 000 символов.

Кодировки на основе Unicode

Unicode можно себе представить как огромную таблицу символов. В памяти компьютера записываются не сами символы, а номера из таблицы. Записывать их можно разными способами. Именно для этого на основе Unicode разработаны несколько кодировок, которые отличаются способом записи номера символа Unicode в виде набора байт. Они называются UTF — Unicode Transformation Format. Есть кодировки постоянной длины, например, UTF-32, в которой номер любого символа из таблицы Unicode занимает ровно 4 байта. Однако наибольшую популярность получила UTF-8 — кодировка с переменным числом байт. Она позволяет кодировать символы так, что наиболее распространённые символы занимают 1-2 байта, и только редко встречающиеся символы могут использовать по 4 байта. Например, все символы таблицы ASCII занимают ровно по одному байту, поэтому текст, написанный на английском языке с использованием кодировки UTF-8, будет занимать столько же места, как и текст, написанный с использованием таблицы символов ASCII.

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

Резюме

  • Кодировка — это соответствие между визуальными символами и числами.
  • Кодировки необходимы, так как компьютеры созданы для работы с числами и не понимают текст.
  • До 1990-х годов не существовало единой кодировки, это приводило к тому, что текст, написанный в одной кодировке, становится совершенно нечитаемым на других.
  • Unicode — единый стандарт кодирования символов. Развитие интернета и необходимость обмена большим количеством текстовой информации приводило к тому, что сейчас все пользуются этим стандартом.
  • UTF-8, UTF-16, UTF-32 и т.п. — это варианты кодировок, основанные на Unicode. Отличаются они тем, что по-разному хранят информацию.
  • UTF-8 — самая популярная кодировка. Особенность её в том, что самые популярные символы кодируются 1-2 байтами, а редко встречающиеся занимают 3-4 байта. Это приводит к существенной экономии памяти, например, при работе с английским текстом.

Как работают кодировки текста. Откуда появляются «кракозябры». Принципы кодирования. Обобщение и детальный разбор

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

Чтобы получить детальное понимание этого вопроса придется прочитать и свести воедино не одну статью и потратить довольно значительное время на это. В данном материале же это все собрано воедино и по идее должно сэкономить время и разбор на мой взгляд получился довольно подробный.

О чем будет под катом: принцип работы одно байтовых кодировок (ASCII, Windows-1251 и т.д.), предпосылки появления Unicode, что такое Unicode, Unicode-кодировки UTF-8, UTF-16, их отличия, принципиальные особенности, совместимость и несовместимость разных кодировок, принципы кодирования символов, практический разбор кодирования и декодирования.

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

Предпосылки Unicode

Начать думаю стоит с того времени когда компьютеризация еще не была так сильно развита и только набирала обороты. Тогда разработчики и стандартизаторы еще не думали, что компьютеры и интернет наберут такую огромную популярность и распространенность. Собственно тогда то и возникла потребность в кодировке текста. В каком то же виде нужно было хранить буквы в компьютере, а он (компьютер) только единицы и нули понимает. Так была разработана одно-байтовая кодировка ASCII (скорее всего она не первая кодировка, но она наиболее распространенная и показательная, по этому ее будем считать за эталонную). Что она из себя представляет? Каждый символ в этой кодировке закодирован 8-ю битами. Несложно посчитать что исходя из этого кодировка может содержать 256 символов (восемь бит, нулей или единиц 2 8 =256).

Первые 7 бит (128 символов 2 7 =128) в этой кодировке были отданы под символы латинского алфавита, управляющие символы (такие как переносы строк, табуляция и т.д.) и грамматические символы. Остальные отводились под национальные языки. То есть получилось что первые 128 символов всегда одинаковые, а если хочешь закодировать свой родной язык пожалуйста, используй оставшуюся емкость. Собственно так и появился огромный зоопарк национальных кодировок. И теперь сами можете представить, вот например я находясь в России беру и создаю текстовый документ, у меня по умолчанию он создается в кодировке Windows-1251 (русская кодировка использующаяся в ОС Windows) и отсылаю его кому то, например в США. Даже то что мой собеседник знает русский язык, ему не поможет, потому что открыв мой документ на своем компьютере (в редакторе с дефолтной кодировкой той же самой ASCII) он увидит не русские буквы, а кракозябры. Если быть точнее, то те места в документе которые я напишу на английском отобразятся без проблем, потому что первые 128 символов кодировок Windows-1251 и ASCII одинаковые, но вот там где я написал русский текст, если он в своем редакторе не укажет правильную кодировку будут в виде кракозябр.

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

Небольшой практикум ASCII

Возможно покажется элементарщиной, но раз уж решил объяснять все и подробно, то это надо.

Вот таблица символов ASCII:

Тут имеем 3 колонки:

  • номер символа в десятичном формате
  • номер символа в шестнадцатиричном формате
  • представление самого символа.

Unicode

С предпосылками создания общей таблицы для всех в мире символов, разобрались. Теперь собственно, к самой таблице. Unicode — именно эта таблица и есть (это не кодировка, а именно таблица символов). Она состоит из 1 114 112 позиций. Большинство этих позиций пока не заполнены символами, так что вряд ли понадобится это пространство расширять.

Разделено это общее пространство на 17 блоков, по 65 536 символов в каждом. Каждый блок содержит свою группу символов. Нулевой блок — базовый, там собраны наиболее употребляемые символы всех современных алфавитов. Во втором блоке находятся символы вымерших языков. Есть два блока отведенные под частное использование. Большинство блоков пока не заполнены.

Итого емкость символов юникода составляет от 0 до 10FFFF (в шестнадцатиричном виде).

Записываются символы в шестнадцатиричном виде с приставкой «U+». Например первый базовый блок включает в себя символы от U+0000 до U+FFFF (от 0 до 65 535), а последний семнадцатый блок от U+100000 до U+10FFFF (от 1 048 576 до 1 114 111).

Отлично теперь вместо зоопарка национальных кодировок, у нас есть всеобъемлющая таблица, в которой зашифрованы все символы которые нам могут пригодиться. Но тут тоже есть свои недостатки. Если раньше каждый символ был закодирован одним байтом, то теперь он может быть закодирован разным количеством байтов. Например для кодирования всех символов английского алфавита по прежнему достаточно одного байта например тот же символ «o» (англ.) имеет в юникоде номер U+006F, то есть тот же самый номер как и в ASCII — 6F в шестнадцатиричной и 111 в десятеричной. А вот для кодирования символа «U+103D5» (это древнеперсидская цифра сто) — 103D5 в шестнадцатиричной и 66 517 в десятеричной, тут нам потребуется уже три байта.

Решить эту проблему уже должны юникод-кодировки, такие как UTF-8 и UTF-16. Далее речь пойдет про них.

UTF-8

UTF-8 является юникод-кодировкой переменной длинны, с помощью которой можно представить любой символ юникода.

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

Немного отступлю от темы, надо написать про совместимость ASCII и UTF

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

Давайте возьмем символ «o»(англ.) из примера про ASCII выше. Помним что в таблице ASCII символов он находится на 111 позиции, в битовом виде это будет 01101111 . В таблице юникода этот символ — U+006F что в битовом виде тоже будет 01101111 . И теперь так, как UTF — это кодировка переменной длины, то в ней этот символ будет закодирован одним байтом. То есть представление данного символа в обеих кодировках будет одинаково. И так для всего диапазона символов от 0 до 128. То есть если ваш документ состоит из английского текста то вы не заметите разницы если откроете его и в кодировке UTF-8 и UTF-16 и ASCII (прим. в UTF-16 такие символы все равно будут закодированы двумя байтами, по этому вы не увидите разницы, если ваш редактор будет игнорировать нулевые байты), и так до момента пока вы не начнете работать с национальным алфавитом.

Сравним на практике как будет выглядеть фраза «Hello мир» в трех разных кодировках: Windows-1251 (русская кодировка), ISO-8859-1 (кодировка западно-европейских языков), UTF-8 (юникод-кодировка). Суть данного примера состоит в том что фраза написана на двух языках. Посмотрим как она будет выглядеть в разных кодировках.

В кодировке ISO-8859-1 нет таких символов «м», «и» и «р».

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

Будем считать что изначально фраза была записана в кодировке Windows-1251. Исходя из таблицы выше запишем эту фразу в двоичном виде, в кодировке Windows-1251. Для этого нам потребуется всего только перевести из десятеричной или шестнадцатиричной системы (из таблицы выше) символы в двоичную.

01001000 01100101 01101100 01101100 01101111 00100000 11101100 11101000 11110000
Отлично, вот это и есть фраза «Hello мир» в кодировке Windows-1251.

Теперь представим что вы имеете файл с текстом, но не знаете в какой кодировке этот текст. Вы предполагаете что он в кодировке ISO-8859-1 и открываете его в своем редакторе в этой кодировке. Как сказано выше с частью символов все в порядке, они есть в этой кодировке, и даже находятся на тех же местах, но вот с символами из слова «мир» все сложнее. Этих символов в этой кодировке нет, а на их местах в кодировке ISO-8859-1 находятся совершенно другие символы. А конкретно «м» — позиция 236, «и» — 232. «р» — 240. И на этих позициях в кодировке ISO-8859-1 находятся следующие символы позиция 236 — символ «ì», 232 — «è», 240 — «ð»

Значит фраза «Hello мир» закодированная в Windows-1251 и открытая в кодировке ISO-8859-1 будет выглядеть так: «Hello ìèð». Вот и получается что эти две кодировки совместимы лишь частично, и корректно перекодировать строку из одной кодировке в другую не получится, потому что там просто напросто нет таких символов.

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

Работает она следующим образом. Первый бит каждого байта кодирующего символ отвечает не за сам символ, а за определение байта. То есть например если ведущий (первый) бит нулевой, то это значит что для кодирования символа используется всего один байт. Что и обеспечивает совместимость с ASCII. Если внимательно посмотрите на таблицу символов ASCII то увидите что первые 128 символов (английский алфавит, управляющие символы и знаки препинания) если их привести к двоичному виду, все начинаются с нулевого бита (будьте внимательны, если будете переводить символы в двоичную систему с помощью например онлайн конвертера, то первый нулевой ведущий бит может быть отброшен, что может сбить с толку).

01001000 — первый бит ноль, значит 1 байт кодирует 1 символ -> «H»

01100101 — первый бит ноль, значит 1 байт кодирует 1 символ -> «e»

Если первый бит не нулевой то символ кодируется несколькими байтами.

Для двухбайтовых символов первые три бита должны быть такие — 110

110 10000 10 111100 — в начале 110, значит 2 байта кодируют 1 символ. Второй байт в таком случае всегда начинается с 10. Итого отбрасываем управляющие биты (начальные, которые выделены красным и зеленым) и берем все оставшиеся ( 10000111100 ), переводим их в шестнадцатиричный вид (043С) -> U+043C в юникоде равно символ «м».

для трех-байтовых символов в первом байте ведущие биты — 1110

1110 1000 10 000111 10 1010101 — суммируем все кроме управляющих битов и получаем что в 16-ричной равно 103В5, U+103D5 — древнеперситдская цифра сто ( 10000001111010101 )

для четырех-байтовых символов в первом байте ведущие биты — 11110

11110 100 10 001111 10 111111 10 111111 — U+10FFFF это последний допустимый символ в таблице юникода ( 100001111111111111111 )

Теперь, при желании, можем записать нашу фразу в кодировке UTF-8.

UTF-16

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

Начнем с символов которые кодируются одной кодовой парой. Легко посчитать что таких символов может быть 65 535 (2в16), что полностью совпадает с базовым блоком юникода. Все символы находящиеся в этом блоке юникода в кодировке UTF-16 будут закодированы одной кодовой парой (двумя байтами), тут все просто.

символ «o» (латиница) — 00000000 01101111
символ «M» (кириллица) — 00000100 00011100

Теперь рассмотрим символы за пределами базового юникод диапазона. Для их кодирования потребуется уже две кодовые пары (4 байта). И механизм их кодирования немного сложнее, давайте по порядку.

Для начала введем понятия суррогатной пары. Суррогатная пара — это две кодовые пары используемые для кодирования одного символа (итого 4 байта). Для таких суррогатных пар в таблице юникода отведен специальный диапазон от D800 до DFFF. Это значит, что при преобразовании кодовой пары из байтового вида в шестнадцатиричный вы получаете число из этого диапазона, то перед вами не самостоятельный символ, а суррогатная пара.

Чтобы закодировать символ из диапазона 1000010FFFF (то есть символ для которого нужно использовать более одной кодовой пары) нужно:

  1. из кода символа вычесть 10000(шестнадцатиричное) (это наименьшее число из диапазона 1000010FFFF)
  2. в результате первого пункта будет получено число не больше FFFFF, занимающее до 20 бит
  3. ведущие 10 бит из полученного числа суммируются с D800 (начало диапазона суррогатных пар в юникоде)
  4. следующие 10 бит суммируются с DC00 (тоже число из диапазона суррогатных пар)
  5. после этого получатся 2 суррогатные пары по 16 бит, первые 6 бит в каждой такой паре отвечают за определение того что это суррогат,
  6. десятый бит в каждом суррогате отвечает за его порядок если это 1 то это первый суррогат, если 0, то второй

Для примера зашифруем символ, а потом расшифруем. Возьмем древнеперсидскую цифру сто (U+103D5):

  1. 103D510000 = 3D5
  2. 3D5 = 0000000000 1111010101 (ведущие 10 бит получились нулевые приведем это к шестнадцатиричному числу, получим 0 (первые десять), 3D5 (вторые десять))
  3. 0 + D800 = D800 ( 110110 0 000000000 ) первые 6 бит определяют что число из диапазона суррогатных пар десятый бит (справа) нулевой, значит это первый суррогат
  4. 3D5 + DC00 = DFD5 ( 110111 1 111010101 ) первые 6 бит определяют что число из диапазона суррогатных пар десятый бит (справа) единица, значит это второй суррогат
  5. итого данный символ в UTF-16 — 1101100000000000 1101111111010101
  1. переведем в шестнадцатиричный вид = D822DE88 (оба значения из диапазона суррогатных пар, значит перед нами суррогатная пара)
  2. 110110 0 000100010 — десятый бит (справа) нулевой, значит первый суррогат
  3. 110111 1 010001000 — десятый бит (справа) единица, значит второй суррогат
  4. отбрасываем по 6 бит отвечающих за определение суррогата, получим 0000100010 1010001000 (8A88)
  5. прибавляем 10000 (меньшее число суррогатного диапазона) 8A88 + 10000 = 18A88
  6. смотрим в таблице юникода символ U+18A88 = Tangut Component-649. Компоненты тангутского письма.

Вот некоторые интересные ссылки по данной теме:
habr.com/ru/post/158895 — полезные общие сведения по кодировкам
habr.com/ru/post/312642 — про юникод
unicode-table.com/ru — сама таблица юникод символов

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

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