UTF-16 () е формат за символно кодиране на всички възможни символи от 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-битови кодови единици, наричани сурогатни (заместващи) двойки, по следната схема: + UTF-16 decoder Горен \ Долен сурогат DC00 DC01 ... DFFF D800 010000010001...0103FF D801 010400010401...0107FF ⋮ ⋮⋮⋱⋮ DBFF 10FC0010FC01...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+00240000 0000 0010 01000000 0000 0010 0100002400 2424 00€ U+20AC0010 0000 1010 11000010 0000 1010 110020AC20 ACAC 20𐐷 U+104370001 0000 0100 0011 01111101 1000 0000 00011101 1100 0011 0111D801DC37D8 01DC 3701 D837 DC𤭢 U+24B620010 0100 1011 0110 00101101 1000 0101 00101101 1111 0110 0010D852DF62D8 52DF 6252 D862 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.