Наборы символов, кодировки и кракозябры

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


Текст состоит из символов, поэтому для представления текста в компьютере, то есть его кодирования с помощью двоичных цифр 0 и 1, нужно уметь кодировать символы. Существуют различные способы кодирования символов, наиболее популярным из которых сейчас является стандарт Юникод (Unicode). Юникод включает в себя знаки практически всех языков мира. Первая версия стандарта Юникод была принята в 1991 году, а в 2020 году была принята его 13-я версия. Основные отличия версий состоят в том, что в них появляются новые письменности и новые символы. В первой версии было 24 письменности и 7161 символ, а в 13-й версии — 154 письменности и 143 859 символов.

Прообразами современных методов кодирования являются азбука Морзе (1838 год), в которой символы кодируются с помощью точек и тире, а также шрифт Брайля (1824 год), в котором символы кодируются с помощью 6 или 8 точек.

ASCII

В 1963 году в США была разработана и утверждена таблица ASCII (American Standard Code for Information Interchange, американский стандартный код для обмена информацией). В английском языке 26 букв, таким образом, для представления больших и маленьких букв, цифр, знаков арифметических операций и знаков препинания достаточно около 100 символов. Поэтому сначала для представления одного символа отводилось 7 бит. Этого достаточно для представления 128 символов с кодами от 0 до 127. Каждому символу сопоставляется некоторый код, в результате чего получается таблица, которая называется набором символов (character set или charset). В качестве синонима часто используется термин кодировка (encoding) и кодовая страница (code page), хотя этот термин правильнее использовать только для однобайтных кодировок.

Для передачи и хранения информации в основном используются группировки бит по 8 (8 бит составляют один байт). В коде ASCII 8-й бит использовался как вспомогательный для контроля ошибок (бит чётности), которые могли возникнуть при передаче или хранении информации.

Бит чётности выставляется в 0 или 1 так, чтобы общее число единичных бит было чётным. Например, код буквы A — 65 или 1000001. Тогда бит чётности будет равен 0 и 8-битный код будет 01000001. Код символа пробел имеет значение 32 или 0100000. Тогда бит чётности будет равен 1 и 8-битный код пробела будет 10100000.

С распространением компьютеров появилась необходимость в расширении количества символов. Было предложено множество различных решений. Так, например, вместо строчных английских букв добавлялись символы национальных языков. Однако в русском языке 33 буквы, поэтому исключали букву Ё, а схожие по начертанию буквы заменялись английскими: А, В, Е, К, М, Н, О, Р, С, Т, Х. Другой способ состоял в использовании специальных управляющих символов SO и SI (Shift Out и Shift In) с кодами 14 и 15 для переключения языка. Однако удобнее оказалось решение с отказом от бита чётности и использование 8 бит для кодирования 256 символов с кодами от 0 до 255. При этом первая половина таблицы ASCII с кодами от 0 до 127 была всегда одинаковой и использовалась для кодирования управляющих символов, арифметических знаков, знаков препинания, цифр и букв английского алфавита.

Управляющих символов в таблице ASCII всего 33: это символы с кодами от 0 до 31 и символ с кодом 127. У управляющих символов нет визуального изображения. В первоначальной версии таблицы ASCII от 1963 года управляющих символов было 29, а в версии 1967 года добавили еще 4 символа. Многие из управляющих символов уже утратили своё значение и стандарт POSIX требует, чтобы только 8 из них поддерживались. Вот эти символы:

  • символ NULL с кодом 0 - пустой символ. В некоторых языках программирования этот символ используется для обозначения конца строки;
  • символ BEL с кодом 7 издаёт звуковой сигнал;
  • cимвол BS (BackSpace) с кодом 8 — удаление предыдущего символа;
  • символ TAB с кодом 9 — горизонтальная табуляция, используется для выравнивания текста. Обычно этим символом задаётся красная строка;
  • символ LF (Line Feed, перевод строки) с кодом 10 — переход на строку вниз;
  • символ VT (Vertical Tab) с кодом 11 — вертикальная табуляция;
  • символ FF (Form Feed) с кодом 12 — переход на новую страницу;
  • символ CR (Carriage Return, возврат каретки) с кодом 13 — переход на начало строки.

Конец строки в разных операционных системах может кодироваться по-разному. Например, в операционных системах семейства UNIX это символ LF, а в операционных системах семейства Windows и MS DOS — это два символа: CR LF.

Наконец, самый загадочный управляющий символ с кодом 127, про который часто забывают, — это символ DEL, удаляющий текущий символ.

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

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

Заглавные английские буквы начинаются с кода 65 (коды буквы A), а строчные — с кода 97 (код буквы а).

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

Для русского языка было предложено несколько кодовых таблиц:

  • CP866 (IBM Code Page 866, Альтернативная кодировка ГОСТ) — реализована в операционных системах MS-DOS, начиная с версии 4.01, также частично используется в Windows;
  • CP1251 (Windows-1251) — используется в системах Windows (кроме подсистемы MS-DOS);
  • KOI8-R (КОИ-8, Код Обмена Информацией) — использовался в операционных системах семейства UNIX;
  • MacCyrillic — использовалась на компьютерах Macintosh.

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

КОДИРОВКА (CP1251) соответствует ╩╬─╚╨╬┬╩└ (CP866);

Вопрос (KOI8-R) соответствует бНОПНЯ (CP1251).

Чтобы прочитать такой текст, его нужно перекодировать из одной кодировки в другую. С развитием сети Интернет проблема с различными кодировками стала очень ощутимой. Также требовалось добавление новых символов. Таблица ASCII содержит всего 256 различных символов, поэтому требовалось новое решение.

Unicode

Стандарт Unicode (Юникод или Уникод) был предложен в 1991 году. Основная идея стандарта в увеличении количества кодируемых символов за счёт увеличения кодового пространства. Вместо одного байта в стандарте Юникод символы могут занимать 2 и более байт. Символы с кодами от 0 до 127 соответствуют символам набора ASCII. Стандарт продолжает развиваться, и в его новые версии добавляются новые символы и письменности. Например, в 10-й версии (2017 год) был добавлен символ биткойна ₿, добавлено много символов эмодзи. В первой версии было 24 письменности и 7 161 символ, а в последней 13-й версии (2020 год) — 154 письменности и 143 859 символов.

Для практического использования было создано несколько семейств кодировок (Unicode transformation format, UTF): UTF-8, UTF-16, UTF-32.

Очень популярной является кодировка UTF-8, которая обеспечивает совместимость с 7-битной системой ASCII: символы ASCII с кодами от 0 до 127 в формате UTF-8 остаются без изменений и также занимают один байт. Остальные символы Юникода кодируются последовательностями длиной от 2 до 4 байт. Таким образом, код UTF-8 является неравномерным.

Кодировка UTF-16 каждому символу сопоставляет последовательность двухбайтовых (то есть 16-битных) слов. Обычно используется 2 или 4 байта для одного символа.

Кодировка UTF-32 каждому символу сопоставляет код длиной 4 байта (то есть 32-бита). Этот код является равномерным.

В кодировках UTF-16 и UTF-32 можно указывать порядок следования байт: младший байт может записываться перед старшим (little-endian, UTF-16LE, UTF-32LE), либо после старшего (big-endian, UTF-16BE, UTF-32BE).

Например:

Латинская буква A в таблице ASCII имеет код 65 или в двоичном виде 01000001.

В кодировке UTF-8 она будет кодироваться точно также.

В кодировке UTF-16BE код будет состоять из двух байт 00000000 01000001 или 0 65, а в кодировке UTF-16LE — 01000001 00000000 или 65 0.

В кодировке UTF-32BE код будет состоять из четырёх байт 00000000 00000000 00000000 01000001 или 0 0 0 65, а в кодировке UTF-32LE — 01000001 00000000 00000000 00000000 или 65 0 0 0.

Для указания, какая кодировка используется, в начале текстового файла может передаваться маркер последовательности байтов BOM (byte order mark) длиной от 2 до 4 байт, который может иметь следующие значения:

  • UTF-8 EF BB BF
  • UTF-16BE FE FF
  • UTF-16LE FF FE
  • UTF-32BE 00 00 FE FF
  • UTF-32LE FF FE 00 00

 

Если вы внимательно прочитали статью, то вам не составит труда пройти конкурс из 10 вопросов на портале Эрудит.Онлайн «Кодирование символьной информации»!

К списку статей