Кодировка текстов в памяти ЭВМ

Договоримся, что текстом называется последовательность букв — элементов некоторого множества \(A\), называемого алфавитом.

Стандарт ASCII

American Standard Code for Information Interchange (коротко ASCII) — стандартизированное соответствие между 128-символьным алфавитом и целыми числами от 0 до 127 (называемыми кодами соответствующих букв).

Полезно знать следующие особенности ASCII:

  • Первые 32 символа — «управляющие»; к ним относятся, например, «переход на новую строчку», «возврат каретки», «колокольчик» и прочее подобное
  • Цифры от 0 до 9 имеют последовательные коды (от 48 до 57)
  • Буквы латинского алфавита имеют последовательные коды; коды заглавных букв на 32 меньше кодов аналогичных маленьких букв

Кодировки ASCII

Вообще для (равномерной) кодировки текста, состоящего из ASCII-символов, достаточно 7 бит на букву. Тем не менее, поскольку сейчас повсеместно в байте 8 бит, то для кодировки одной ASCII-буквы используются все 8 бит. При этом обычно старший бит оставляют равным 0.

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

  • при использовании какого-нибудь расширения кодировки ASCII единичный старший бит означает, что данный символ не из ASCII, а из дополнительной части алфавита
  • как контрольный (например, бит чётности); впрочем, сейчас такое почти не встречается

Ещё с кодировками ASCII связано название кнопки клавиатуры Ctrl: исторически нажатие на эту кнопку обнуляло 4 старших бита кода одновременно нажатой цифро-буквенной клавиши, предоставляя таким образом доступ к «управляющим» (ConTRoL) символам.

Исторические кодировки для русского языка

Сейчас всё ещё можно изредка встретить три 8-битных расширения ASCII, используемых для кодировки русских текстов:

  • CP866 (оно же dos)
  • CP1251 (оно же win)
  • KOI8-R

Первая кодировка (CP866) малопримечательна и устроена весьма непривычно: например, коды заглавных русских букв от кодов маленьких отличаются совсем не на 32, да и идут русские буквы не подряд.

Дополнительная часть второй кодировки (CP1251) устроена аналогично ASCII: русские буквы идут подряд, а коды заглавных и строчных букв отличаются на 32, кроме буквы ё, которая стоит особняком (в русском алфавите 33 бувы, и одной пришлось пожертвовать).

Кодировка KOI8-R наиболее интересно устроена: в ней русские буквы расположены так, что при обнулении старшего бита у всех букв текст сохраняет читаемость (при вычитании 128 из кода русской буквы получается код похожего по написанию символа ASCII).

Стандарт Unicode

Сейчас Unicode — это фактически общепринятый стандарт, определяющий понятие буквы (в терминах самого Unicode буквы именуются кодовыми точками).

Кодовые точки нумеруются числами от \(0\) до \(2^{20}+2^{16}-1\) за исключением диапазона от \(D800_{16}\) до \(DFFF_{16}\), который для нумерации кодовых точек не используется.

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

UTF-32

Семейство UTF-32 состоит из двух кодировок:

  • в кодировке UTF-32-LE каждая кодовая точка записывается 256-ричным представлением своего номера с LE-порядком байт (от младших к старшим)
  • в кодировке UTF-32-BE каждая кодовая точка записывается 256-ричным представлением своего номера с BE-порядком байт (от старших к младшим)

Иногда текстовые данные в одной из этих кодировках сопровождаются меткой порядка байт в качестве первой буквы текста. Метка порядка байт имеет номер \(FEFF_{16}\). То есть, если текст начинается с байт

FF FE 00 00

то это означает, что используется кодировка UTF-32-LE.

Если же текст начинается с байт

00 00 FE FF

то это означает использование UTF-32-BE.

UTF-8

Наиболее распространённой в интернете сейчас является кодировка UTF-8. Она работает так:

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

Список представлений:

  • 0??????? (1 байт для кодовых слов длины не более 7 бит)
  • 110????? 10?????? (2 байта для кодовых слов длин от 8 бит до 11 бит)
  • 1110???? 10?????? 10?????? (3 байта для кодовых слов длин от 12 бит до 16 бит)
  • 11110??? 10?????? 10?????? 10?????? (4 байта для кодовых слов длин от 17 бит до 21 бита)

Биты кодовой точки дополняются слева нулями до нужно длины, после чего вписываются вместо ?.

Для примера покажем, как закодировать метку порядка байт (хотя в UTF-8 она смысла не имеет). У неё номер равен

\[ FEFF_{16} = 1111\,1110\,1111\,1111_{2} \]

В нём 16 бит, поэтому нужно использовать третье представление:

FEFF -> 1111 1110 1111 1111
       /   / |  | |  |  \  \
      /   /  |  | |   \ |  |
     /   /   /  | /    \|  |
    /   /   /   //     ||  |
    1111    111011    111111
1110????  10??????  10??????

11101111  10111011  10111111
E   F     B   B     B   F

Итого мы получили байты EF BB BF (именно в таком порядке!).

UTF-16

На уроках мы не рассматривали это семейство кодировок, знание его устройства не требуется, но приведено для полноты картины.

Этих кодировок, как и UTF-32, две штуки: с LE и BE порядками байт.

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

Кодовые точки с номерами, не превышающими \(FFFF_{16}\), записываются одной кодовой единицей, совпадающей с номером.

Кодовые точки с номерами, большими \(FFFF_{16}\), записываются так:

  • из номера вычитается \(2^{16}\)
  • оставшиеся не более чем 20 бит номера дополняются слева ведущими нулям и вписываются в нижеприведённую схему
начальная кодовая единица  |  конечная кодовая единица
110110??  ????????         |  110111??  ????????

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