Цель состоит в том, чтобы создать полностью совместимый конвертер между официальными кодировками Unicode, как указано в FAQ UTF . Учитывая, что это сосредоточено на Unicode, я приму ответ с самым низким количеством байтов, используя наилучшее из возможных кодировок (которое, вероятно, будет UTF-8, если, возможно, вы не запрограммируете его в APL). Я прошу прощения за длинный пост, но во многом он объясняет кодировки, которые также доступны в официальной спецификации (pdf, раздел 3.9 D90 - D92) или в Википедии .
Характеристики
Если в любой момент выбранный вами язык не может точно соответствовать требованию, замените его чем-то, что соответствует духу данных правил. Например. не каждый язык имеет встроенные массивы, функции и т. д.
Не используйте строковые библиотеки / функции или кодирование библиотек / функций. Смысл этого кода в том, чтобы реализовать преобразователь с использованием битовых / байтовых манипуляций. Однако использование самих строк в качестве символьного или байтового массива допускается. Да, и никаких вызовов ОС, которые также выполняют преобразование.
Преобразователь - это функция, которая принимает три параметра: байтовый массив, представляющий кодированную входную строку, и кодировки «вход» и «выход», представленные в виде чисел. Мы будем произвольно назначать
UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF32LE
числа от 0 до 6 в этом порядке. Нет необходимости проверять, является ли число< 0
или> 6
, мы будем считать эти параметры правильными. Преобразователь вернет действительный байтовый массив в желаемой выходной кодировке.Мы будем использовать нулевой символ (
U+0000
) в качестве ограничителя строки. Все, что после этого не имеет значения. Мы будем предполагать, что входной массив где-то имеет нулевой символ, поэтому вам не нужно выполнять проверку границ.Согласно FAQ , если входной байтовый массив недопустим для объявленной кодировки, мы должны сообщить об ошибке. Мы сделаем это одним из следующих способов: завершить работу программы, вызвать исключение, вернуть ноль или вернуть массив, первые четыре байта которого равны 0 (чтобы его можно было распознать как
U+0000
в любой кодировке).
Кодировки
Должны соблюдаться официальные спецификации, но Википедия дает хорошее (и, насколько я считаю, правильное) объяснение кодировок, и я приведу их здесь для полноты. Обратите внимание, что UTF-16 и UTF-32 имеют варианты для порядка байтов .
UTF-32, UTF-32LE, UTF-32BE
В простейшем кодировании каждая кодовая точка просто кодируется в 4 байта, равных его числовому значению. LE / BE представляет собой порядковый номер (little endian / big endian).
UTF-16, UTF-16LE, UTF-16BE
Кодовые точки из U+0000 - U+FFFF
кодируются в 2 байта, равного его числовому значению. Большие значения кодируются с использованием пары суррогатов, которые являются зарезервированными значениями из U+D800 - U+DFFF
. Поэтому для кодирования точек больше чем U+FFFF
можно использовать следующий алгоритм (бесстыдно скопированный из Википедии ):
- 0x010000 вычитается из кодовой точки, оставляя 20-битное число в диапазоне 0..0x0FFFFF.
- Десять старших битов (число в диапазоне 0..0x03FF) добавляются к 0xD800, чтобы дать первую единицу кода или суррогатный вывод, который будет в диапазоне 0xD800..0xDBFF [...].
- Десять младших битов (также в диапазоне 0..0x03FF) добавляются к 0xDC00, чтобы получить вторую единицу кода или суррогат следа, который будет в диапазоне 0xDC00..0xDFFF [...].
UTF-8,
Кодовые точки из U+0000 - U+007F
кодируются как 1 байт, равный его числовому значению. Из U+0080 - U+07FF
них кодируются как 110xxxxx 10xxxxxx
, U+0800 - U+FFFF
это 1110xxxx 10xxxxxx 10xxxxxx
, более высокие значения 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
. Это x
биты из числового значения кодовой точки.
BOM
Метка порядка байтов (BOM, U+FEFF
) используется в качестве первой кодовой точки для указания порядка байтов. В соответствии с рекомендациями FAQ по спецификациям, спецификация будет использоваться следующим образом: UTF-8, UTF-16 and UTF-32
она не является обязательной. Если в UTF-16
или отсутствует спецификация UTF-32
, предполагается, что она является прямым порядком байтов. Спецификация не должна появляться в UTF-16LE, UTF-16BE, UTF-32LE and UTF-32BE
.
Распространенные ошибки, приводящие к неверному UTF
Различные вещи могут привести к тому, что последовательность байтов будет недействительной UTF.
- UTF-8 и UTF-32: прямое кодирование суррогатных кодовых точек (
U+D800 - U+DFFF
) или кодовых точек, превышающихU+10FFFF
. - UTF-8: много недопустимых байтовых последовательностей.
- UTF-16: непарные или неправильно спаренные суррогаты.
- Спецификация: должна использоваться, как указано в разделе кодирования. Обратите внимание, что при выводе
UTF-16
илиUTF-32
(без указания присущего порядка байтов) вы можете выбрать, но с прямым порядком байтов, вы должны включить спецификацию.
Обратите внимание, что не-символы и неназначенные кодовые точки (отличные от суррогатов) должны обрабатываться как обычные символы.
''⎕R''⍠'InEnc' 'UTF16BE' 'OutEnc' 'UTF8-BOM'
.