UTF16

UTF-16 (англ. Unicode Transformation Format) в информатике — один из способов ирования символов из Юниа в виде последовательности 16-битных слов.

Данная ировка позволяет записывать символы Юниа в диапазонах U+0000..U+D7FF и U+E000..U+10FFFF (общим количеством 1 112 064). При этом каждый символ записывается одним или двумя словами (суррогатная пара). ировка UTF-16 описана в приложении Q к международному стандарту ISO/IEC 10646, а также ей посвящён IETF RFC 2781 «UTF-16, an encoding of ISO 10646».


История появления[ | ]

Первая версия Юниа (1991 г.) представляла собой 16-битную ировку с фиксированной шириной символа; общее число разных символов было 216 (65 536). Во второй версии Юниа (1996 г.) было решено значительно расширить овую область; для сохранения совместимости с теми системами, где уже был реализован 16-битный Юни, и была создана UTF-16. Область 0xD800—0xDFFF, отведённая для суррогатных пар, ранее принадлежала к области «символов для частного использования».

Поскольку в UTF-16 можно отобразить 220+216−2048 (1 112 064) символов, то это число и было выбрано в качестве новой величины ового пространства Юниа.

Принцип ирования[ | ]

DC00 DFFE DFFF
D800 010000 0103FE 0103FF
D801 010400 0107FE 0107FF
DBFF 10FC00 10FFFE  

В UTF-16 символы ируются двухбайтовыми словами с использованием всех возможных диапазонов значений (от 0 до FFFF16). При этом можно ировать символы Unicode в диапазонах 000016..D7FF16 и E00016..FFFF16. Исключенный отсюда диапазон D80016..DFFF16 используется как раз для ирования так называемых суррогатных пар — символов, которые ируются двумя 16-битными словами.

Символы Unicode до FFFF16 включительно (исключая диапазон для суррогатов) записываются как есть 16-битным словом.

Символы же в диапазоне 1000016..10FFFF16 (больше 16 бит) ируются по следующей схеме:

  • Из а символа вычитается 1000016. В результате получится значение от нуля до FFFFF16, которое помещается в разрядную сетку 20 бит.
  • Старшие 10 бит (число в диапазоне 000016..03FF16) суммируются с D80016, и результат идёт в ведущее (первое) слово, которое входит в диапазон D80016..DBFF16.
  • Младшие 10 бит (тоже число в диапазоне 000016..03FF16) суммируются с DC0016, и результат идёт в последующее (второе) слово, которое входит в диапазон DC0016..DFFF16.

Порядок байтов[ | ]

Один символ ировки UTF-16 представлен последовательностью двух байтов или двух пар байтов. Который из двух байтов идёт впереди, старший или младший, зависит от порядка байтов. Систему, совместимую с процессорами x86, называют little endian, а с процессорами m68k и SPARC — big endian.

Для определения порядка байтов используется метка порядка байтов (англ. Byte order mark). В начале текста записывается U+FEFF. При считывании, если вместо U+FEFF считалось U+FFFE, значит порядок байтов обратный (little endian), поскольку U+FFFE в Юние не ирует символ и зарезервирован как раз для целей определения порядка байтов. Так как в ировке UTF-8 не используются значения 0xFE и 0xFF, можно использовать метку порядка байтов как признак, позволяющий различать UTF-16 и UTF-8.

UTF-16LE и UTF-16BE[ | ]

Предусмотрена также возможность внешнего указания порядка байтов — для этого ировка должна быть описана как UTF-16LE или UTF-16BE (little-endian / big-endian), а не просто UTF-16. В этом случае метка порядка байтов (U+FEFF) не нужна.

UTF-16 в ОС Windows[ | ]

В API Win32, распространённом в современных версиях операционной системы Microsoft Windows, имеется два способа представления текста: в форме традиционных 8-битных овых страниц и в виде UTF-16.

При использовании UTF-16, Windows не накладывает ограничений на прикладные программы касательно ирования текстовых файлов, позволяя им использовать как UTF-16LE, так и UTF-16BE посредством установки и трактовки соответствующей метки порядка байтов. Однако внутренний формат Windows — всегда UTF-16LE. Этот момент следует учитывать при работе с исполняемыми файлами, использующими юниовые версии функций WinAPI. Строки в них всегда ируются в UTF-16LE[1].

В файловых системах NTFS, а также FAT с поддержкой длинных имён, имена файлов записываются также в UTF-16LE.

Примеры процедур[ | ]

Примеры ниже записаны на псевдое и в них не учитывается маска порядка байтов — они лишь показывают суть ирования. Порядок байтов — от младшего к старшему (Little-Endian, интеловский x86). Тип Word — двухбайтовое слово (16-битное беззнаковое целое), а тип UInt32 — 32-битное беззнаковое целое. Шестнадцатеричные значения начинаются со знака доллара «$».

ирование[ | ]

В примере WriteWord() — условная процедура, которая пишет одно слово (при этом сдвигает внутренний указатель). Функция LoWord() возвращает младшее слово от 32-битного целого (старшие биты не глядя отбрасываются).

// Допустимые значения Code: $0000..$D7FF, $E000..$10FFFF.
Procedure WriteUTF16Char(Code: UInt32)
    If (Code < $10000) Then
        WriteWord(LoWord(Code))
    Else
        Code = Code - $10000
        Var Lo10: Word = LoWord(Code And $3FF)
        Var Hi10: Word = LoWord(Code Shr 10)
        WriteWord($D800 Or Hi10)
        WriteWord($DC00 Or Lo10)
    End If
End Procedure

Деирование[ | ]

В примере ReadWord() читает слово из потока (сдвигая при этом внутренний указатель). Она же при необходимости может корректировать порядок байтов. Функция WordToUInt32 расширяет двухбайтовое слово до четырёхбайтового беззнакового целого, заполняя старшие биты нулями. Error() прерывает выполнение (по сути исключение).

// В случае успеха возвращаются значения
// в диапазонах $0000..$D7FF и $E000..$10FFFF.
Function ReadUTF16Char: UInt32
    Var Leading:  Word  // Лидирующее (первое) слово.
    Var Trailing: Word  // Последующее (второе) слово.

    Leading = ReadWord();
    If (Leading < $D800) Or (Leading > $DFFF) Then
        Return WordToUInt32(Leading)
    Else If (Leading >= $DC00) Then
        Error("Недопустимая овая последовательность.")
    Else
        Var Code: UInt32
        Code = WordToUInt32(Leading And $3FF) Shl 10
        Trailing = ReadWord()
        If ((Trailing < $DC00) Or (Trailing > $DFFF)) Then
            Error("Недопустимая овая последовательность.")
        Else
            Code = Code Or WordToUInt32(Trailing And $3FF)
            Return (Code + $10000)
        End If
    End If
End Function

Примечания[ | ]

Ссылки[ | ]