Восемь лет спустя
kv75
дневник заведен 05-10-2003
постоянные читатели [82]
закладки:
цитатник:
дневник:
местожительство:
Москва, Россия
интересы [13]
шахматы, грибы, Пратчетт, Иваси, Morrowind, Guild Wars
[1] 08-05-2008 07:37
Альпы

[Print]
Элизабет
Среда, 3 Октября 2007 г.
11:20 Кодировочные новости
Во-первых, сегодня утром я обнаружил, что на моём компьютере нет PDF'ов Unicod'a 5.0. Я решил, что это непорядок, и скачал книжку, базу данных и таблицы символов. Поскольку таблицы символов я скачивал целиком (всю директорию), заодно попался очень любопытный файл, своего рода пасхальное яйцо.

Во-вторых, вчера я разобрался таки с непонятным вложением. Смысл был в том, что на почтовый адрес пришли три письма. В первом была строка "begin 666 fn.rar" (имя файла из соображений конспирации заменено на fn), после которой начинался текст, несколько напоминаший Base64. Тоже фиксированная длина строки, но каждая строка начиналась с «литеры M». Второе письмо, очевидно, содержало продолжение (уже без всякого бегина), а в конце третьего письма содержалась строка "end". Поиск в интернете показал, что это кодировка uuencoded. После объединения всех строк Total Commander прекрасно расшифровал файлы, но рар-архив отказался распаковываться. При тщательном изучении исходников было выяснено, что некоторые строки файла имеют другую длину, начинаясь при этом с того же символа M, причём первый символ строки кодирует её длину (как в стандартном Паскале). Очевидно, Thunderbird при сохранении немного наврал, приняв что-то за служебные последовательности. Тогда я взял исходную БД Thunderbird'а, благо его внутренний формат хранения совпадает с серверным оригиналом, и вытащил оттуда три нужных письма. После их объединения и раскодирования распаковка рара прошла успешно.
Четверг, 25 Мая 2006 г.
22:47 Unicode
Итак, я решил написать обзорную статейку, посвящённую некоторым вопросам юникода. Самым сложным моментом в написании является перевод стандартных юникодовских терминов, но мне кажется, что я с этим более-менее справился.

Юникод – стандарт, определяющий соответствие между адресами юникода (Unicode code points) и символами. Всего существует 1112064 (=2^20+2^16-2^11) адресов юникода – это адреса от 0 до $10FFFF (я всегда буду указывать диапазоны "включительно"), исключая диапазон $D800–$DFFF. Шестнадцатеричные числа мне удобнее всего обозначать в паскалевском стиле – знаком $ перед числом. Об исключенном диапазоне и причинах его исключения я буду подробно говорить ниже.

Все адреса юникода делятся на присвоенные (Assigned code points), которым уже поставлены в соответствие символы, и неприсвоенные (Unassigned или reserved code points). Присваивание адресов идёт в два этапа. Сначала для символов того или иного алфавита или класса выделяется блок (диапазон адресов), далее этот блок постепенно заполняется символами. Число адресов в блоке всегда кратно 16; кроме того, блоки зачастуют выделяются с запасом для дальнейшего расширения; поэтому во многих блоках до сих пор имеются (и будут присутствовать далее) неприсвоенные адреса.

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

Во-первых, это общедоступные адреса. К ним относятся все символы (как печатные, так и служебные), значение которых однозначно (а иногда не вполне однозначно) определено и которые могут использоваться в любых строках. На сегодняшний день (все данные я указываю по бета-версии Unicode 5.0) стандартом определено 99089 общедоступных адресов.

Во-вторых, это частные адреса (Private code points). Их значение по определению не регламентируется стандартом юникода. Значения этих адресов могут определяться пользователями (как разработчиками ОС, так и конечными пользователями) по своему усмотрению. Соответствующие символы вполне могут использоваться в любых строках, но взаимопонимания между различными программами никто не гарантирует – для этого их разработчики должны приложить собственные усилия. Стандартом предусмотрено 137468 частных адресов. На мой взгляд, этого всем должно хватить за глаза.

В-третьих, это запрещённые адреса (Noncharacter code points). Это адреса, которым не соответствует и никогда не будет соответствовать никакой символ. Такой символ в нормальной ситуации программа не может ни получить извне, ни выдать в строке результата. Запрещённых адресов насчитывается 66. Пожалуй, единственная область их применения – внутри программ, где запрещённый символ, используемый для служебных целей, гарантированно не сможет смешаться с легальными.

Адреса юникода для удобства описания и дальнейшего присвоемия, как уже было сказано, группируются в блоки. Блоки группируюся в плоскости (Planes). Плоскость с номером N – это диапазон адресов в интервале $N0000–$NFFFF, где 0≤N≤$10. Таким образом, существует 17 плоскостей, каждая из которых, кроме плоскости 0, содержит 65536 адресов юникода. Нулевая плоскость содержит 63488 (=2^16-2^11) адресов.

Распределение символов по плоскостям показано на первом рисунке. Как видно, нулевая (основная многоязычная плоскость) уже почти заполнена: не распределены по блокам всего 2544 адресов, а в имеющихся блоках не присвоено 2430 адресов. Только начала заполняться первая плоскость (вспомогательная многоязычная плоскость). Вторая плоскость (вспомогательная идеографическая плоскость) заполнена почти на две трети – туда вошли редко используемые символы CJK. Плоскость №14, предназначенная для различных вспомогательных символов (вроде кодов форматирования) также в самом начале заполнения. Полностью отданы под частные адреса две последние плоскости. Плоскости 3–13 пока и не думали заполняться, если не учитывать адресов вида $NFFFE и $NFFFF, которые во всех плоскостях объявлены запрещёнными адресами.

Как же адреса юникода физически представляются в компьютере? Для этого существует три кодировки: UTF-32, UTF-16 и UTF-8.

Самой простой и удобной в наше время, хотя и далеко не самой экономной, является кодировка UTF-32, каждый адрес юникода в которой представляется четырехбайтовым словом. Конечно, реально из 32 бит используется только 21. Все слова, значения которых выходят за рамки адресов юникода, в этой кодировке являются нелегальными.

Кодировка UTF-16 работает с двухбайтовыми словами. При этом все 63488 символов нулевой плоскости кодируются "как есть" одним словом, а символы остальных плоскостей кодируются двумя словами, первое из которых лежит в диапазоне $D800–$DBFF, а второе – в диапазоне $DC00–$DFFF. Нетрудно убедиться, что сочетаниями этих двух слов можно закодировать ровно $100000 (=$400*$400) символов. Собственно, именно по этой причине (ради удобства кодировки UTF-16) диапазон $D800–$DFFF был исключен из адресов юникода. Коды в этом диапазоне называются суррогатными, а пары суррогатных кодов, кодирующие адреса юникода высших плоскостей – суррогатными парами.

Надо отметить, что исторически кодировка UTF-16 была основной, и первая версия юникода предусматривала только одну (нулевую) плоскость. Но времена изменились, понадобилось больше символов, и во второй версии были введены ещё 16 плоскостей, а диапазон $D800–$DFFF пришлось сделать суррогатным. С тех пор кодировка UTF-16 является не основной, а всего лишь одной из трёх равноправных кодировок.

Не могу не упомянуть о проблеме формулировок, которая может затмить знаменитую проблему "массы покоя" (кто в последние годы слушал Л.Б.Окуня, поймёт, что я имею в виду). Зачастую в описаниях стандарта диапазон $D800–$DFFF указывается в качестве "блока, выделенного под суррогатные адреса". Я настаиваю на том, что это вредная формулировка! Диапазон суррогатных кодов не является блоком! Это не адреса юникода, и они в этом смысле ничем не отличаются от кодов от $110000 до бесконечности.

Ну и, наконец, кодировка UTF-8, самая сложная в реализации из всех трёх. Она работает с байтами. Адреса от 0 до $007F в ней кодируются напрямую одним байтом; адреса от $0080 до $07FF (в т.ч. символы русского алфавита) – двумя байтами; адреса с $0800 по $FFFF – тремя; с $10000 по $10FFFF – четырьмя. При этом в многобайтовой последовательности первый байт принадлежит диапазону $C2–$F4, а остальные байты – $80–$BF, так что пропустить начало и конец символа невозможно.

С кодировкой UTF-8 связана проблема множественных кодировок символов, нашедшая отражение в вопросах безопасности. Дело в том, что если алгоритм декодирования символов составлен недостаточно корректно, он может воспринять формально нелегальную последовательность байт и декодировать её в адрес юникода. Например, адрес $0041 (латинская буква "A") может быть декодирован не только из легальной для UTF-8 последовательности $41, но и из трёх нелегальных последовательностей: $C1 $81, $D0 $81 $81, $F0 $80 $81 $81. Эти три последовательности объявлены нелегальными чисто волюнтаристским решением. Сделано это для того, чтобы обеспечить взаимную однозначность отображения адресов юникода на множество легальных последовательностей UTF-8. В результате этого самой сложной частью алгоритма декодирования UTF-8 является именно проверка на легальность.

Главное в написании статьи – вовремя закончить её. Я умышленно не стал рассматривать множество интереснейших вопросов. Например, назначение различных блоков и их распределение по адресам; классификация общедоступных адресов юникода по типу символов и подсчёт символов разных типов; различные свойства символов; подробное описание алгоритмов кодирования… Может быть, если у меня и у читателей будет взаимный интерес к какому-нибудь из этих вопросов, будет продолжение.
Среда, 24 Мая 2006 г.
00:03 Уфф
Досчитал!

Теперь (т.е. в ближайшие дни) буду писать запись про Юникод. Возможно, разобью на несколько записей, если обнаружу, что материал легко делится на логические части.
Вторник, 23 Мая 2006 г.
00:19 Вопрос к читателям
Вот уже несколько дней я анализирую текущее состояние Юникода. По итогам анализа я неизбежно напишу запись. Запись эта возможна в двух вариантах. Либо это будут просто цифры без определений (т.е. для себя), либо подробное (от печки) описание большинства затрагиваемых моментов. Внимание, вопрос: интересна ли кому-нибудь запись второго типа? Если да, то буду писать её.
Воскресенье, 21 Мая 2006 г.
11:00 Воскресное утро
Сейчас пойдём заряжать камеру. Со следующей недели начнём активную работу.

Вчера вечером скачал символы из бета-версии Unicode 5. Нового там пока очень мало; разве что имеет смысл выделить появление блока клинописи в первой плоскости (SMP). Впрочем, и в кириллических блоках появилось 11 новых символов. А вообще новых символов введено маловато, конечно. Плоскости с 3 по 13 так и остаются девственно чистыми.
Закрыть