Калина Алексей блог программиста

Кодировки, брр...

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

Вводная

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

ASCII

С этой кодировки, расшифровывающейся как American Standard Code for Information Interchange, мы начнем наше погружение в тему. В стандартном ASCII используется только 7 бит, следовательно таблица символов содержит 128 символов. Среди них - латинские буквы, арабские цифры, знаки препинания и различные служебные символы. Причем эти 128 символов являются стандартом, который соблюдается в большинстве других кодировок.

Однако, на свете есть множество других языков кроме английского, а в байте 8 бит… Поэтому появилось большое число расширений ASCII, которые задействовали оставшиеся 128 символов под нужды своего алфавита. Также существуют и другие 7-битные кодировки, которые ориентированы на конкретный алфавит. Рассмотрим некоторые из подобных семейств.

КОИ

КОИ-8 (код обмена информацией) была широко распространена как основная русская кодировка в Unix-подобных системах. Она расширяла код ASCII таким образом, что буквы русского алфавита располагались в нижней части таблицы на тех же позициях, что и созвучные им английские. Таким образом, если убрать последний бит для каждого символа из текста, написанном в кодировке КОИ-8, получится текст в транслите. Есть несколько вариантов этой кодировки, для разных алфавитов стран СНГ (KOI8-R, KOI8-U, KOI8-T).

Интересной особенностью этой и некоторых других кодировок того времени (CP866) является наличие среди символов различной псевдографики (палочки, уголочки и так далее). Это связано с тем, что она создавалась тогда, когда были распространены неграфические операционные системы. Тем не менее, текст, написанный в КОИ-8 можно встретить до сих пор. Также существует 7-битный вариант этой кодировки (КОИ-7), который, соответственно, не поддерживает стандарт ASCII, поэтому изжил себя уже достаточно давно.

ISO-8859

Еще одно семейство однобайтовых ASCII-совместимых кодировок. Содержит порядка пятнадцати кодовых страниц для разных языков, в том числе и кириллицу (ISO-8859-5). Так как разрабатывалась как средство обмена информацией, она не предназначена для обеспечения высококачественной типографики, при этом содержит много символов управления терминалом. Также как и предыдущее семейство, ISO-8859 использовалось как правило в юниксоподобных системах, хотя в России была распространена именно КОИ-8.

Windows

В Windows существует свой набор кодовых страниц, который используется как стандартный в этой ОС. К слову, в MacOS таковой является Mac Cyrillic или Mac Roman. В данном же случае кодировки носят название Windows-125*. Это также восьмибитные варианты ASCII. Для отображения кириллицы используется кодировка Windows-1251, с которой собственно у меня и были проблемы при индексации текстовых файлов.

Глядя на эту картину, мне становится не по себе. При таком обилии кодировок, я не нашел какого-либо эффективного способа проверки того, в какой кодировке был написан конкретный текст. Тем не менее, еще в 1991 году было предложено логичное решение, благодаря которому сейчас все не так уж и плохо.

Unicode

Именно в 1991 году был создан консорциум Юникод. Благодаря ему был создан стандарт с одноименным названием, который объединял все кодировки. Юникод - это огромная таблица из 1 114 112 элементов, содержащая всевозможные символы, и в которой достаточно места для будущих языков. Однако, это не кодировка, это только кодовая таблица. Другими словами, Юникод говорит о символе только то, под каким номером он стоит в таблице, а каким образом представлять его в байтах уже задача кодировок, о которых мы и поговорим далее.

UTF

Для кодирования такого числа символов нужно не менее трех байт. По понятным причинам программистам все же ближе число 4, поэтому на свет появился UTF-32, в котором под каждый символ отведено 32 бита. При таком подходе очевидна проблема: если пользователь использует только символы из таблицы ASCII, UTF-32 будет хранить в 4 раза больше данных, чем этого требуется.

Для решения этой проблемы были придуманы кодировки с переменной длинной: UTF-8 и UTF-16. UTF-8 позволяет кодировать символы длиной от 1 до 4 байтов. При этом старшие биты сообщают о том, какого размера этот символ. Для ASCII символов происходит экономия памяти, но за счет сигнальных символов двухбайтные значения могут превратиться в трехбайтные. Альтернативой этой кодировке является UTF-16, минимальная длина символа в которой равна двум байтам и может увеличиваться до четырех.

При работе с текстовыми файлами с кодировками, поддерживающими Юникод, иногда существует возможность понять как закодирован текст по первым байтам документа. Маркер последовательности байтов (Byte Order Mark, BOM), расположенный в начале файла, позволяет определить кодировку и порядок байтов (Big/Little Endian). Однако, нужно учитывать, что UTF документы могут и не иметь BOM.

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

Заключение

Обилие несовместимых кодировок, из-за которых мы видим вместо текста “крокозябры”, по-прежнему доставляет пользователям проблемы. Однако, благодаря Юникоду сегодня они уже не стоят столь остро. Надеюсь, этот небольшой обзор был вам полезен.