Цель состоит в том, чтобы создать полностью совместимый конвертер между официальными кодировками 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'
.Ответы:
C ++, (UTF-8) 971 байт
Читаемую ниже программу можно сжать до приведенной выше формы, отфильтровав ее с помощью следующей команды Perl:
Вышеуказанная команда
#include
строкЧитаемый код
Функция, которая должна быть вызвана
t()
, с кодировкой ввода и вывода, передаваемой в глобальные переменныеi
и,o
соответственно, иp
указывающей на байты ввода, которые должны заканчиваться нулем.q
указывает на выходной буфер, который будет перезаписан и должен быть достаточно большим для результата - нет попытки избежать переполнения буфера.Я надеюсь, что комментарии к коду достаточно объяснительны - спросите ниже, если один из них слишком загадочный (но сначала приложите усилие!).
Я разработал обширный набор тестов, разрабатывая этот ответ; Я включил его ниже для удобства других участников и документировал свое толкование требований:
Тестовые функции
Тестирование
источник
Питон - 1367 символов UTF-8
Хорошо! Это был чрезвычайно сложный вопрос из-за огромного объема работы, необходимой для понимания и реализации всех спецификаций, но я думаю, что у меня правильная реализация.
convert
это функция, которая принимает объект данных «байты», идентификатор ввода и идентификатор вывода. Кажется, это работает - хотя Python, кажется, немного не использует спецификации, когда они не указаны в кодировке, поэтому использование встроенной кодировки Python для тестирования режимов 1 и 4 не будет работать.Интересный факт: размер также 555 16 или 10101010101 2 .
773 символа для декодирования, 452 для кодирования, 59 для проверки и 83 для разных частей.
источник
Python 3, 1138 байт (UTF-8)
Вот и получается, что 14 часов международных путешествий - это фантастическая возможность завершить игру в гольф ...
Функция преобразования есть
C()
. Это вызываетu()
,v()
и,w()
чтобы декодировать, иU()
, иV()
, иW()
кодировать, UTF-8, -16 и -32, соответственно. Ни один из кодировщиков не выведет спецификацию, но все декодеры будут правильно обрабатывать ее. Состояния ошибки приводят к исключению (как правилоZeroDivisionError
, из-за функции «внезапно умереть»E()
).источник