Представление текстовых данных
– Вы можете прочитать третью снизу строку таблицы?
– Н, К, И, М… Доктор, у вас криво настроена кодировка!
Все используемые способы представления текстовых данных, так или иначе, сводятся к нумерации символов алфавита (или множества символов системы письменности интересующего нас языка, которое используется вместо алфавита – слоговой азбуки, иероглифов и т. д.) и хранения полученных целых чисел наравне с обычными числами. Способ нумерации называется кодировкой, а числа – кодами символов.
Для большинства кодировок языков, использующих алфавитную письменность (латиница, кириллица, арабский алфавит, еврейский и греческий языки) достаточно 127 символов. Самая распространенная система кодирования латиницы – ASCII – использует 7 бит на символ. Другие алфавиты обычно кодируются более сложным образом: символы алфавита получают коды в диапазоне от 128 до 255, а коды от 0 до 127 соответствуют кодам ASCII.
Таким образом, любой символ этих алфавитов, в том числе и в многоязычных текстах, использующих сочетание национального алфавита и латиницы, может быть представлен 8-ю битами или одним байтом. Но для японских слоговых азбук, а тем более для китайской иероглифики, 255 кодов явно недостаточно, и приходится использовать многобайтовые кодировки. Распространенное обозначение таких кодировок – DBCS (Double Byte Character Set – набор символов, кодируемый двумя байтами).
Двух байтов, в принципе, достаточно, чтобы сформировать единую кодировку для всех современных алфавитов и основных подмножеств иероглифики. Попытка стандартизовать такое представление – Unicode – пока что не имеет полного успеха. Отчасти это можно объяснить тем, что потребность в представлении разноязыких текстов в пределах одного документа ограничена, кроме того, слишком много старого программного обеспечения использует предположение о том, что символ занимает не более байта. Такие программы не могут быть легко преобразованы для работы с Unicode.
Используются две основные кодировки латиницы – ASCII и EBCDIC (Extended Binary Coded Decimal Information Code), применяемая системами AS/400, System/370, System/390 и z90 фирмы IBM. Для представления русского варианта кириллицы существует три основных кодировки: альтернативная (известная также как ср866), ср1251 и KOI-8 и ряд менее широко используемых (ISO 8892-5 и др.).
Арифметические операции над такими "числами" обычно бессмысленны, зато большой смысл имеют операции сравнения. Операции сравнения в современных процессорах реализованы как неразрушающее вычитание – мы производим те же действия, что и при обычном двоичном вычитании, но запоминаем не сам результат, а лишь флаги знака, переноса и равенства результата нулю. На основании значений этих флагов определяем результат сравнения: если разность равна нулю, сравниваемые символы одинаковы, если она положительна или отрицательна, один из символов больше или меньше другого.
Естественно, чаще всего мы хотим интерпретировать результаты посимвольного сравнения как лексикографическое (алфавитное) "больше" или "меньше" (для русского алфавита, "а" меньше, чем "б"). Проще всего это делать, если нумерация символов совпадает с их порядком в алфавите, но далеко не для всех распространенных кодировок это справедливо.
В кодировке ASCII (American Standard Code for Information Interchange – Американский стандартный код обмена информацией), например, все символы латиницы, цифры и большинство распространенных знаков препинания обозначаются кодами от 0 до 127, при этом коды букв расставлены в соответствии с латинским алфавитом. В США, как и в других англоязычных странах, латинский алфавит используется в неизмененном виде, а для передачи звуков, отсутствовавших в оригинальном латинском языке, применяется причудливая орфография. Большинство других европейских алфавитов обходит проблему несоответствия фонетик путем расширения набора символов латиницы – например, в немецком языке добавлены буквы ö, ä, ü и ß.
Другие языки имеют множество различных "акцентов" и "диакритических символов", расставляемых над буквами для указания особенностей произношения. Некоторые языки, например французский, используют одновременно и расширения алфавита, и причудливую орфографию. Нередко встречаются и дополнительные знаки препинания, например, ¿ и ¡ в испанском языке.
Все символы-расширения в каждом из национальных алфавитов находятся на определенных местах, но при использовании кодировки ASCII для представления этих символов сохранить этот порядок невозможно – соответствующие коды уже заняты. Так, в кодировке ISO 8895-1 все символы латиницы кодируются в соответствии с ASCII, а коды расширений более или менее произвольно раскиданы между 128 и 255. Более яркий пример той же проблемы – кодировки кириллицы семейства KOI, в которых символы кириллицы сопоставлены фонетически соответствующим им символам латиницы (филе нот фоунд, или, наоборот, esli wy не movete proсitatx eto po-russki, smenite kodirovku). Естественно, совместить такое сопоставление и алфавитную сортировку невозможно.
Стандартным решением в таких случаях является использование для сравнения и лексикографической сортировки промежуточных таблиц, в которых для каждого допустимого кода указан его номер в лексикографическом порядке. На уровне системы команд процессоры этого обычно не делают, но на уровне библиотек языков высокого уровня это осуществляется очень часто.
При обмене данными между системами, использующими разные кодировки, необходимо учитывать этот факт. Стандартный способ такого учета, применяемый во многих кросс-платформенных форматах документов (HTML, MIME) – это сообщение где-то в теле документа (обычно в его начале) или в передаваемой вместе с документом метаинформации об используемых языке и кодировке. Большинство средств просмотра почты и документов HTML умеют интерпретировать эту метаинформацию, поэтому конечный пользователь все реже и реже сталкивается с необходимостью самостоятельно разбираться в различных кодировках.
Проблемы возникают, когда метаинформация не указана или, что еще хуже, указана неправильно. Последнее особенно часто встречается при неправильной настройке почтового клиента у отправителя. Для борьбы с такими сообщениями разработаны даже специальные программы, применяющие частотный анализ текста для определения реально использованной кодировки.
Два основных подхода к представлению форматированного текста – это языки разметки и сложные структуры данных, используемые в текстовых процессорах. Примерами языков разметки являются HTML, LATEX, troff. В этих языках обычный текст снабжается командами, указывающими на то, каким шрифтом следует отображать конкретный фрагмент текста и как его следует форматировать (например, какова ширина параграфа, следует ли делать переносы в словах, надо ли выравнивать текст по левому или правому краю). Команды представляют собой специальные последовательности символов той же кодировки, в которой набран и основной текст.
Отформатированные таким образом тексты могут генерироваться как вручную (например, LATEX ориентирован именно на ручной набор текста), так и различными автоматизированными средствами.