Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Unicode. Другие кодировки Unicode




Unicode

Unicode был смелой попыткой создать единственный набор символов, который включал бы все реальные системы письма, существующие на планете, а также некоторые выдуманые. Некоторые люди имеют неправильное представление, что Unicode – это обычный 16-битовый код, где каждый символ занимает 16 битов и поэтому есть 65, 536 возможных символов. На самом деле это не верно. Это самый распространенное ошибочное представление о Unicode.

Фактически, Unicode содержит необычный подход к пониманию понятия символ. До сих пор мы предполагали, что символы отображаются на набор каких-то битов, которые вы можете хранить на диске или в памяти:

A -> 0100 0001

В Unicode символ отображается на нечто, называемое кодовой точкой (code point), которая является всего лишь теоретическим понятием. Как эта кодовая точка представлена в памяти или на диске — это отдельная история. В Unicode буква A это всего лишь платонова идея (эйдос) (прим. пер.: понятие философии Платона, эйдосы – это идеальные сущности, лишённые телесности и являющиеся подлинно объективной реальностью, находящиеся вне конкретных вещей и явлений).

A Эта платонова A отличается от B, и отличается от a, но это та же самая A, что и A и A. Идея, что А в шрифте Times New Roman является тем же самым, что и А в шрифте Helvetica, но отличается от строчной " a", не кажется слишком спорной в понимании людей. Но с точки зрения компьютерных наук и с точки зрения языка само определение буквы противоречиво. Немецкая буква ß – это настоящая буква или всего лишь причудливый способ написать ss? Если написание буквы, стоящей в конце слова, изменяется, она становится другой буквой? Иврит говорит да, арабский говорит нет. Так или иначе, умные люди в консорциуме Unicode поняли это, после большого количества политических дебатов, и вы не должны волноваться об этом. Все уже понято до нас.

Каждой платоновой букве в каждом алфавите консорциумом Unicode было назначено волшебное число, которое записывается так, как это: U+0645. Это волшебное число называют кодовой точкой. U+ означает " Unicode", а числа являются шестнадцатеричными. Число U+FEC9 является арабской буквой Аин (Ain). Английская буква A соответствует U+0041.

В действительности нет никакого предела для количества букв, которые могут определяться через Unicode, и на самом деле они уже перешагнули за пределы 65, 536, так что не каждая буква из Unicode может действительно сжиматься в два байта.

Для кириллицы в UNICODE отведен диапазон кодов от 0x0400 до 0x04FF. В данной таблице приведена лишь часть знаков этого диапазона, однако стандартом определено большинство кодов этого диапазона.

Представим, что мы имеем строку:

Привет!

которая, в Unicode, соответствует этим семи кодовым точкам:

U+041F U+0440 U+0438 U+0432 U+0435 U+0442 U+0021

Всего лишь набор кодовых точек. Числа в действительности.

Чтобы узнать, как будет выглядеть текстовый файл в формате Unicode, можно запустить программу notepad в Windows, вставить данную строку и при сохранении текстового файла выбрать кодировку Unicode.

Программа предлагает сохранение в трех разновидностях кодировок Unicode. Первый вариант представляет собой способ записи с младшим байтом впереди (little endian), второй со старшим байтом впереди (big endian). Какой из вариантов является правильным?

Вот как выглядит дамп файла со строкой “Привет! ”, сохраненный в формате Unicode (big endian):

А так выглядит дамп файла со строкой “Привет! ”, сохраненный в формате Unicode (little endian):

А так выглядит дамп файла со строкой “Привет! ”, сохраненный в формате Unicode (UTF-8):

Ранние реализации хотели быть в состоянии хранить кодовые точки Unicode в формате с первым старшим байтом и первым младшим байтом (high-endian or low-endian), в зависимости от того, с каким форматом именно их процессор работал быстрее. Тогда возникло два способа хранить Unicode. Это привело к появлению причудливого соглашения о хранении кода \uFFFE в начале каждой строки Unicode. Эту сигнатуру называют меткой порядка байтов (byte order mark). Если вы поменяете местами ваши старший и младший байты, то в начале должно стоять \uFFFE, и человек, читающий вашу строку, будет знать, что он должен поменять байты в каждой паре местами. Данная сигнатура является зарезервированной в стандарте Unicode.

В стандарте Unicode написано, что порядок байт по умолчанию является либо big endian, либо little endian. Действительно, оба порядка являются правильным, и разработчики систем сами выбирают себе один из них. Не стоит беспокоиться, если ваша система обменивается данными с другой системой и обе используют little endian.

Однако, если ваша Windows обменивается данными с UNIX-сервером, который использует big endian, одна из систем должна осуществлять перекодировку. В этом случае стандарт Unicode гласит, что можно выбрать любой из следующих способов решения проблемы:

  1. Когда две системы, использующие различный порядок представления байт в Unicode, обмениваются данными (не используя каких-то специальных протоколов), то порядок байт должен быть big endian. В стандарте это называется каноническим (canonical) порядком байт.
  2. Каждая строка Unicode должна начинаться с кода \uFEFF. Код \uFFFE, который является “перевертыванием” знака порядка. Поэтому если получатель видит в качестве первого символа код \uFEFF, то это значит, что байты находятся в перевернутом (little endian) порядке. Тем не менее, в реальности, не каждая строка Unicode имеет в начале метку порядка байтов.

Второй способ является более универсальным и предпочтительным.

Некоторое время казалось, что все довольны, но англоязычные программисты рассматривали в основном английский текст и редко использовали кодовые точки выше U+00FF. По одной только этой причине Unicode многими игнорировался в течение нескольких лет.

Специально для этого была изобретена блестящая концепция UTF-8.

UTF-8

UTF-8 был другой системой хранения вашей последовательности кодовых точек Unicode, тех самых U+ чисел, используя те же 8 битов в памяти. В UTF-8 каждая кодовая точка с номерами от 0 до 127 сохранялись в единственном байте.

По сути, это кодировка с переменным количеством кодирующих байтов для хранения используется 2, 3, и, фактически, до 6 байтов. Если символ принадлежит набору ASCII (код в интервале 0x00-0x7F), то он кодируется так же как в ASCII одним байтом. Если юникод символа больше или равен 0x80, то его биты упаковываются в последовательность байтов по следующему правилу:

Интервал Unicode (шестнадцатиричный) Код UTF-8 (двоичный)
0x0000 – 0x007F 0xxxxxxx
0x0080 – 0x07FF 110xxxxx 10xxxxxx
0x0800 – 0xFFFF 1110xxxx 10xxxxxx 10xxxxxx

Можно заметить, что если байт начинается с нулевого бита, то это однобайтовый символ ASCII. Если байт начинается с 11…, то это стартовый байт несколькобайтовой последовательности, кодирующей символ, число головных единичек которого равно количеству байт в последовательности. Если байт начинается с 10…, то это серийный «транспортный» байт из последовательности байтов, количество которых было определено стартовым байтом. Ну а биты Unicode символа упаковываются в «транспортные» биты стартового и серийных байтов, обозначенные в таблице как последовательность «xx.. x».

В переменном количестве кодирующих байт можно убедиться по нижеприведенному дампу файлов.

Дамп файла со строкой “Hello! ”, сохраненный в формате Unicode (UTF-8):

Дамп файла со строкой “Привет! ”, сохраненный в формате Unicode (UTF-8):

Приятным побочным эффектом этого является то, что английский текст выглядит в UTF-8 точно то же, как и в ASCII, таким образом американцы даже не замечают, что что-то не так. Только вся остальная часть мира должна преодолевать препятствия. Конкретно, Hello, то, которое было U+0048 U+0065 U+006C U+006C U+006F, теперь будет сохранено в тех же 48 65 6C 6C 6F, так же как и в ASCII, и ANSI, и любом другом наборе символов OEM на планете. Если же вы столь смелы, чтобы использовать диакритические символы или греческие буквы или буквы Klingon, вы должны будете использовать несколько байтов для хранения единственной кодовой точки, но американцы никогда этого не заметят. UTF-8 также имеет хорошую особенность: старый код, неосведомленный о новом формате строк, и обрабатывающий строки с нулевом байтом в конце строки, не будет усекать строки.

Другие кодировки Unicode

Возвратимся к трем способам кодировать Unicode. Традиционные методы " хранить это в двух байтах" называют UCS-2 (потому что это имеет два байта) или UTF-16 (потому что это имеет 16 битов), и вы еще должны выяснять, является ли это код UCS-2 со старшим байтом в начале или со старшим байтом в конце. И есть популярный стандарт UTF-8, строки на котором имеют приятную особенность также работать и в старых программах, работающих с английским текстом, и в новых умных программах, которые прекрасно оперируют другими наборами символов, кроме ASCII.

 

На самом деле есть еще целый набор других способов закодировать Unicode. Есть нечто, называемое UTF-7, которое сильно походит на UTF-8, но гарантирует, что старший бит всегда будет нолем. Еще есть UCS-4, который хранит каждую кодовую точку в 4 байтах и гарантирует, что абсолютно все символы будут сохранены в одинаковом числе байтов, но такая трата памяти впустую не всегда оправдана такой гарантией.

 

Например, вы можете закодировать в Unicode строку Hello (U+0048 U+0065 U+006C U+006C U+006F) в кодировке ASCII, или в старой греческой кодировке OEM, или в еврейской кодировке ANSI, или в любой из нескольких сотен кодировок, которые были изобретены до наших дней, с одной проблемой: некоторые из символов могут не отображаться! Если нет никакого эквивалента для кодовой точки Unicode, для которой вы пытаетесь найти эквивалент в какой-либо кодовой таблице, для которой вы пытаетесь сделать преобразование, вы обычно получаете небольшой вопросительный знак: ? или, если вы действительно хороший программист, то квадратик.

 

Есть сотни традиционных кодировок, которые могут правильно хранить только некоторые кодовые точки и заменять все остальные кодовые точки вопросительными знаками. Например, некоторые популярные кодировки английского текста - Windows 1252 (стандарт Windows 9x для западноевропейских языков) и ISO-8859-1, он же Латинский-1 (также пригодный для любого западноевропейского языка). Но попытайтесь преобразовать русские или еврейские буквы в этих кодировках, и вы получите изрядное количество вопросительных знаков. Отличной чертой UTF 7, 8, 16, и 32 является их способность правильно хранить любую кодовую точку.

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...