UTF-16
UTF-16 (на английски: Unicode Transformation Format) е формат за символно кодиране на всички възможни символи от Unicode във вид на последователност от 16-битови кодови единици. Кодирането е с променлива дължина, като кодови точки са кодирани с една или две 16-битови кодови единици.
UTF-16 е разработен въз основа на по-ранния формат UCS-2 (Two-byte Universal Character Set), който използва кодови единици с фиксираната дължина от 16 бита. Необходимостта от разработването на новия формат идва, след като се установява, че предходният не е достатъчно универсален, тъй като два байта не са достатъчни, за да се кодират достатъчен брой символи.
История
[редактиране | редактиране на кода]В края на 1980 г. започват усилия по разработване на единно кодиране за „Universal Character Set“ (UCS), което да замени по-ранните кодировки с една координирана система. Целта е да се включат всички необходими символи от повечето световни езици, както и символи от технически области като наука, математика и музика. Първоначалната идея е да се разширят познатите до момента 256-символни кодировки, изискващи 1 байт за символ, с кодиране включващо 216 = 65536 стойности (кодови точки), изискващо 2 байта на знак. Две групи работят по този проект паралелно – Фондацията IEEE и Консорциумът Unicode, като последният представлява най-вече производителите на компютърно оборудване. Двете групи правят опит да синхронизират проектите си, с идеята развиващите се кодировки да бъдат взаимно съвместими, като първоначално 2-байтовото кодиране се е наричало „Unicode“, но е по-познато като „UCS-2“.
Още в началото на процеса по разработка обаче става ясно, че 216 символи не биха били достатъчни и в резултат IEEE въвежда по-голямо 31-битово пространство за кодиране (UCS-4), което използва 4 байта за кодиране на символ. Това среща съпротива от страна на Консорциума Unicode поради факта, че 4 байта на символ биха използвали прекалено много дисково пространство и памет, а и някои производители вече са направили сериозни инвестиции в технологията за 2-байтово кодиране. Като компромис за изход от създалата се ситуация е разработена схемата за кодиране UTF-16, която се появява във версия 2.0 на стандарта Unicode през юли 1996 г. Пълните спецификации на новата схема са посочени в документацията RFC 2781, публикувана през 2000 г. от IETF.
В UTF-16 кодовите точки, по-големи или равни на 216, са кодират с помощта на две 16-битови кодови единици. Организациите по стандартизация решават за такива кодови единици да се използва най-големият блок от незаети (неалокирани със символи) 16-битови кодови единици и така всъщност кодовите точки в обхвата на този блок не могат да бъдат индивидуално кодирани в UTF-16 (както и във всички останали UTF схеми за кодиране).
Техническата спецификация на UTF-16 е определена в последните версии на международния стандарт ISO/IEC 10646 и на стандарта Unicode.
Описание
[редактиране | редактиране на кода]От U+0000 до U+D7FF и от U+E000 до U+FFFF
[редактиране | редактиране на кода]UTF-16, както и UCS-2, кодират кодовите точки в този обхват като 16-битови кодови единици, които са цифрово равни на съответстващите кодови точки. Тези кодови точки от Базисната многоезикова равнина (Basic Multilingual Plane), са единствените, които могат да бъдат представени чрез UCS-2. Един съвременен текст почти винаги се състои от тези кодови точки.
От U+10000 до U+10FFFF
[редактиране | редактиране на кода]Кодови точки от другите равнини (наречени допълващи равнини) са кодирани в UTF-16 като две 16-битови кодови единици, наричани сурогатни (заместващи) двойки, по следната схема:
Горен \ Долен
сурогат |
DC00 | DC01 | ... | DFFF |
---|---|---|---|---|
D800 | 010000 | 010001 | ... | 0103FF |
D801 | 010400 | 010401 | ... | 0107FF |
⋮ | ⋮ | ⋮ | ⋱ | ⋮ |
DBFF | 10FC00 | 10FC01 | ... | 10FFFF |
- Изваждайки 0x010000 от кодовата точка, получаваме 20-битово число в обхвата от 0 до 0x0FFFFF.
- Горните десет бита, представляващи число в обхвата между 0 и 0x03FF, се добавят към 0xD800 и така се получава първата 16-битова кодова единица от двойката, наречена горен сурогат. Горният сурогат е в обхвата 0xD800..0xDBFF.
- Долните десет бита (също в обхвата между 0 и 0x03FF) се добавят към числото 0xDC00, за да дадат втората 16-битова кодова единица, или т.нар. долен сурогат, който е в обхвата 0xDC00..0xDFFF.
В миналото е имало опит горният и долният сурогат да се наричат „водещ“ и „следващ“ поради факта, че техните числови стойности не отговарят на техните имена, но това е изоставено в по-новите стандарти за Unicode.
Тъй като обхватът на горния и долния сурогат и валидните символи от базисната многоезикова равнина са разделени, не е възможно един сурогат да съвпадне със символ от многоезиковата равнина, нито два съседни символа да наподобяват валидна сурогатна двойка. Това значително улеснява търсенето, но и означава, че UTF-16 е самосинхронизиращ се по отношение на 16-битови думи, т.е. не се налага да се изследва предишната кодова единица, за да се определи дали текущата започва определен символ. UTF-8 също има тези предимства, но много ранни многобайтови схеми за кодиране (като Shift JIS или различни азиатски схеми) не позволяват нееднозначно търсене и при тях синхронизирането се получава чрез повторно обхождане от началото на низа (String) (UTF-16 не е самосинхронизиращ се, ако единият от двата байта е загубен или обхождането започва от случаен байт).
Поради факта, че най-често използваните символи попадат в БМР, обработката на сурогатните двойки често не е достатъчно добре тествана. Това води до повтарящи се грешки и възможни пробиви в сигурността, дори в популярни и добре приети потребителски приложения (напр. CVE-2008 – 2938, CVE-2012 – 2135).
Допълващите равнини съдържат допълнителни символи, като емотикони, някои не толкова често използвани китайски йероглифи, исторически азбуки и др.
От U+D800 до U+DFFF
[редактиране | редактиране на кода]Стандартът Unicode запазва за постоянно стойността на тези кодови точки за кодирането на горния и долния сурогат в UTF-16, т.е. на тях никога няма да съответства определен символ и съответно закодирането им е безпредметно. В официалния Unicode стандарт дори е заявено, че никой UTF формат, дори UTF-16, няма право да закодирва тези кодови точки.
Въпреки това UCS-2, UTF-8 и UTF-32, както и голяма част от приложенията, правят именно това, независимо че според стандарта подобно действие би следвало да се третира като грешка в кодирането.
Нееоднозначното кодиране на тези точки в UTF-16 все пак е възможно чрез използване на кодова единица, еднаква на кодовата точка, но само дотолкова, доколкото нито една поредица от две кодови единици не може да бъде интерпретирана като валидна сурогатна двойка (или горен сурогат, следван от долен сурогат). Повечето кодиращи и декодиращи имплементации на UTF-16 работят именно по този начин.
Пример
[редактиране | редактиране на кода]Да вземем за пример кодирането на U+10437 (𐐷):
- Изваждаме 0x10000 от 0x10437. Резултатът е 0x00437,
0000 0000 0100 0011 0111
. - От полученото число вземаме горната 10-битова стойност и долната 10-битова стойност:
0000000001
и0000110111
. - Добавяме 0xD800 към горната стойност, за да получим горния сурогат: 0xD800 + 0x0001 = 0xD801.
- Добавяме 0xDC00 към долната стойност, за да получим долния сурогат: 0xDC00 + 0x0037 = 0xDC37.
Следващата таблица обобщава гореописаните преобразувания, както и други. Цветовете индикират как битовете на кодовите точки се разпределят между байтовете на UTF-16. Допълнителните битове, добавени от кодиращия процес на UTF-16, са показани в черно.
Символ | Кодова точка в двоичен вид | Двоичен вид на UTF-16 | UTF-16 кодови единици в шестнайсетичен вид |
UTF-16BE (биг ендиан) шестнайсетичен вид байтове |
UTF-16LE (литъл ендиан) шестнайсетичен вид байтове | |
---|---|---|---|---|---|---|
$ | U+0024
|
0000 0000 0010 0100
|
0000 0000 0010 0100
|
0024
|
00 24
|
24 00
|
€ | U+20AC
|
0010 0000 1010 1100
|
0010 0000 1010 1100
|
20AC
|
20 AC
|
AC 20
|
𐐷 | U+10437
|
0001 0000 01 00 0011 0111
|
1101 10 00 0000 0001 1101 11 00 0011 0111
|
D801 DC37
|
D8 01 DC 37
|
01 D8 37 DC
|
𤭢 | U+24B62
|
0010 0100 10 11 0110 0010
|
1101 10 00 0101 0010 1101 11 11 0110 0010
|
D852 DF62
|
D8 52 DF 62
|
52 D8 62 DF
|
Байтов порядък на системите за символно кодиране
[редактиране | редактиране на кода]Тъй като форматите UTF-16 и UCS-2 създават последователност от една или две 16-битови кодови единици, а повечето протоколи за прехвърляне и съхраняване на информация са дефиниране за 8-битови байтове, последователността на байтовете зависи от байтовия порядък на компютърната архитектура.
За разползнаване на байтовия порядък UTF-16 използва знак за байтов порядък (Byte Order Mark – BOM), който представлява кодова точка със стойност U+FEFF и предхожда първият кодиран символ. Ако архитектурата за байтов порядък на декодера съвпада с тази в кодирането, декодерът открива U+FEFF стойност, докато декодер с обратен байтов порядък ще интерпретира символа като U+FFFE, който е запазен поради тази причина. Неверният резултат във втория случай ще предизвика размяна на байтовете и коректно декодиране на текста. В случай че знакът за байтов порядък липсва, според RFC 2781 трябва да бъде използвано big-endian декодиране (байтът с най-висок порядък е първият байт). Въпреки това, тъй като операционната система Windows предполага little-end декодиране, при което с най-висок порядък е последният байт, много приложения използват little-end декодиране по подразбиране. Един от методите за разшифриране на байтов порядък при декодиране е търсенето на символа за празен интервал (U+0020), който е често срещан в текстове на различни езици.
Форматът също позволява предварително задаване на байтовия порядък посредством използването на UTF-16BE или UTF-16LE при задаване типа на символното кодиране. При експлицитно задаване на байтовия порядък, използването на знак за байтов порядък (Byte Order Mark – BOM) в началото на текст не е необходимо и знакът U+FEFF се третира като ZWNBSP (zero-width non-breaking space) символ. Много програми игнорират BOM знака в началото на текст, а уеб браузърите често го използват за подсказка при определянето на типа символно кодиране в Unicode текст
За Интернет протоколите, Службата за присвояване на имена и адреси в Интернет (IANA) одобрява следните имена за горепосочените формати – UTF-16", „UTF-16BE“ и „UTF-16LE“. В някои програмни езици възможни и други наименования като UTF_16 и UTF16.
Подобни имена са възприети и за UCS-2 – UCS-2, UCS-2BE и UCS-2LE, имитирайки тези за UTF-16, но UCS-2 е вече остарял и не реферира към стандарта Unicode (ISO/IEC 10646).
Приложение
[редактиране | редактиране на кода]Приложно-програмният интерфейс (API) на операционните системи, разработени от Microsoft след Windows 2000 – Microsoft Windows XP/2003/Vista/7/8/CE използват UTF-16 за кодиране на текстови символи. Изключение прави Windows XP, в която всички включени шрифтове за европейски езици не поддържат символи с код над U+FFFF. По-старите версии, до Windows NT включително, поддържат само UCS-2.
Освен гореспоменатите, UTF-16 и UCS-2 имат широко приложение – в Microsoft .NET Framework, QT крос-платформи, JavaScript, Qualcomm BREW, iPhone. Oперационната система Symbian, Sony Ericsson UIQ използват UCS-2.
IBM iSeries платформите поддържат едновременно UTF-8, UTF-16 и UCS-2, реферирайки към специфични за всеки енкодинг кодови страници (таблици) с поддържаните символи и съответното им байтово кодиране.
Java платформата първоначално използва UCS-2, като впоследствие имплементира използването на UTF-16 след J2SE 5.0.
Файловата система Joliet, използвана в CD-ROM, използва UCS-BME за кодиране имена на файловете.
Езикът Python използва UCS-2. Версия 2.0 преминава към използването и на UTF-8, но декодерът работи коректно и с UTF-16. След версия 3.3, използваните концепции за кодиране на символи са ASCII, UTF-8, UTF-32 и UCS-2.
В много програмни езици кодирането на кодови точки извън базисната многоезикова равнина (non-BMP) се нуждае от нов синтаксис, тъй като добре познатият стандартен "\uXXXX"
е ограничен от само 4 цифри в шестнайсетична бройна система. Най-разпространеният начин, използван в езиците C#[1] и D, е използването на главно U, последвано от 8 цифри в шестнайсетична бройна система – "\U0001D11E"
. В регулярните изрази, използвани в Java 7 (и последващи версии), Perl и ICU трябва да бъде използван синтаксисът "\x{1D11E}"
. В останалите програмни езици (включително и в Java извън използването на регулярни изрази) единственият начин за достъп до символ извън BMP може да бъде осъществено чрез въвеждането на двете 16-битови сурогатни двойки (напр."\uD834\uDD1E"
за U+1D11E
).
Разлика между UTF-32, UTF-16 и UTF-8
[редактиране | редактиране на кода]Основната разлика между трите вида кодиране на символи е в размера на байтовете нужни, за да представляват символ в паметта. UTF-8 използва минимум един байт, за разлика от UTF-16, който използва поне два. Ако кодът на символът е по-голям от максималната стойност на един байт, която е 127, UTF-8 ще използва 2, 3 или 4 байта, но UTF-16 ще употребява винаги два или четири. От друга страна UTF-32 има фиксирана дължина и винаги използва 4 байта. Кодирането на символи (character encoding) е важна концепция от процеса на конвертиране на байтовите потоци в символи, които могат да бъдат изобразени. Има две неща, които са важни за конвертиране на байтове в символи – набор (таблица) от символи и енкодинг (encoding). Тъй като има много символи и различни букви по света, една таблица от символи трябва да поддържа всички тях. Тя не е нищо повече от един лист от символи, където всеки един символ или буква е свързан с уникална за него числова стойност, известна още като кодова точка (code point).
UTF-16, UTF-32 и UTF-8 са кодиращи схеми (encoding schemes), които описват как тези кодови точки са свързани към байтове (използвайки различни битови стойности като база – 16-битова за UTF-16, 32-битова за UTF-32 и т.н.). UTF е съкращение на „Трансформация на Unicode“ (Unicode Transformation), която дефинира алгоритъм за свързването на всяка кодова точка на Unicode към уникална поредица от байтове.
За пример, кодовата точка на Unicode за символа 'А' (латинската главна буква 'А') е U+0041, кодираните байтове за UTF-8 са 41, а за UTF-16 – 0041. Литерал за символ на Java е '\u0041'. За да се преведе потокът от байтове е нужна схема за кодиране на символи (Character Encoding Scheme). В липсата на такава, те няма да бъдат изобразени коректно [2].
Предимства и недостатъци
[редактиране | редактиране на кода]В сравнение с UTF-8
[редактиране | редактиране на кода]Предимства
[редактиране | редактиране на кода]Символите от U+0800 до U+FFFF използват по три байта в UTF-8, но само два в UTF-16. В резултат на това текст, написан (примерно) на китайски, японски или хинди, ще заема повече място в паметта, ако използва UTF-8.
Малко предимство на UTF-16 е, че неправилен UTF-8 декодер може да приеме всички възможни 4-, 5- или дори 6-байтови поредици, вследствие на което да произведе невалидни кодови точки, прехвърляйки лимита до U+10FFFF дефиниран от Unicode. Много по трудно е случайно да се напише UTF-16 декодер с подобна грешка. Въпреки това, тези проблеми не възникват в коректно имплементирани парсъри, които не зачитат невалидни поредици.
Недостатъци
[редактиране | редактиране на кода]Байтов код и UTF-8 са представени от байтови масиви в програми, и в повечето случаи конвертирането в една функция от байтове в UTF-8 е автоматично. UTF-16 е представен от 16-битови масиви от думи и конвертирането към UTF-16, поддържайки съвместимост с програми базирани на ASCII, изисква всеки API (приложно-програмен интерфейс) и структура от данни, които вземат низ (String), да бъдат дублирани. Едната версия ще приема байтови низове, а другата UTF-16.
Кодиран в UTF-8 текст ще заема по-малко памет, отколкото същият текст, кодиран в UTF-16, ако има повече кодови точки под U+0080, отколкото в диапазона от U+0800 до U+FFFF. Това важи за всички съвременни европейски езици. Номера (цифри 0 – 9), интервали, символи за нов ред и символите за маркиране на HTML (HTML markup characters) – всичките са кодови точки под U+0080 и много често това е валидно и за азиатските скриптове.
Вижте също
[редактиране | редактиране на кода]Външни препратки
[редактиране | редактиране на кода]Източници
[редактиране | редактиране на кода]Тази страница частично или изцяло представлява превод на страницата UTF-16 в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите.
ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни. |