Четыре байта на скалярный код: чтение UTF-32LE

Как устроено фиксированное 32-битное хранение UTF-32LE, почему порядок байтов не равен развороту десятичной записи и как прочитать кодовую точку из четырёх байтов, а также где заканчивается применимость формулы «четыре байта на символ».

Четыре байта на скалярный код: чтение UTF-32LE

Назначение

UTF-32 хранит каждый скалярный код Unicode в одном 32-битном коде. Задача читателя, работающего с таким потоком, состоит в том, чтобы по четырём байтам восстановить числовое значение кода и проверить, является ли оно допустимым скаляром. Статья разбирает порядок байтов little-endian, пошагово считывает пример и отделяет числовые позиции в потоке от позиций видимых символов.

Представление данных

Скалярные значения Unicode занимают диапазон от U+0000 до U+10FFFF, при этом диапазон U+D800–U+DFFF исключён: это суррогатные значения, которые не кодируются в UTF-32. Одно 32-битное поле способно принять любое число от 0 до 4294967295, но далеко не каждое из них является валидным скаляром. Декодер обязан отклонять значения вне диапазона U+0000–U+10FFFF.

Little-endian означает, что младший байт числа записывается первым в памяти. Это свойство порядка байтов фиксированной разрядности, а не разворот десятичной записи. Читая байты «слева направо» как цифры, вы получите другое число, и это другое число не обязательно будет валидным Unicode-скаляром.

Чтение кодовой точки

Рассмотрим букву Ё. Её кодовая точка U+0401 в шестнадцатеричном виде 0x00000401. В little-endian байты записываются младшим первым: 01 04 00 00. Аналогично буква Я, U+042F, даёт байты 2F 04 00 00, а латинская A, U+0041, даёт 41 00 00 00.

Пошагово: берём четыре байта подряд, складываем их в 32-битное число, умножая каждый байт на степень 256 по его позиции, считая младший байт нулевой. Для последовательности 01 04 00 00 результат 1×256⁰ + 4×256¹ + 0×256² + 0×256³ = 1025, то есть U+0401.

Ошибка порядка байтов

Если те же байты 01 04 00 00 интерпретировать как big-endian, получается число 0x01040000, то есть 17039360 в десятичной записи. Это значение превышает U+10FFFF, поэтому оно не является валидным скаляром Unicode. Декодер, работающий с big-endian потоком, обязан отклонить его как повреждённое или неверно интерпретированное, а не присвоить ему какой-либо символ.

Скаляр и глиф

Одна кодовая точка не всегда соответствует одному видимому знаку. Композиция «е» с огоньком записывается двумя скалярами: U+0065 и U+0328, то есть восемью байтами в UTF-32LE. Аналогично «е» с острым акцентом в разложенной форме NFD содержит U+0065 и U+0301, но при нормализации NFC сжимается в один скаляр U+00E9. Видимый графемный кластер может состоять из одного или нескольких скалярных значений.