Я хочу использовать Rebol 3 для чтения файла в Latin1 и преобразования его в UTF-8. Есть ли встроенная функция, которую я могу использовать, или какая-то внешняя библиотека? Где я могу это найти?Выполнение преобразования кодировки файла с помощью Rebol 3
ответ
Rebol имеет недопустимый-UTF? Функция, которая проверяет двоичное значение для байта, который не является частью действительной последовательности UTF-8. Мы можем просто цикл, пока мы не нашли и заменили все из них, а затем преобразовать наше двоичное значение в строку:
latin1-to-utf8: function [binary [binary!]][
mark: :binary
while [mark: invalid-utf? mark][
change/part mark to char! mark/1 1
]
to string! binary
]
Эта функция изменяет исходный двоичный файл.Мы можем создать новую строку вместо, которая оставляет двоичное значение нетронутого:
latin1-to-utf8: function [binary [binary!]][
mark: :binary
to string! rejoin collect [
while [mark: invalid-utf? binary][
keep copy/part binary mark ; keeps the portion up to the bad byte
keep to char! mark/1 ; converts the bad byte to good bytes
binary: next mark ; set the series beyond the bad byte
]
keep binary ; keep whatever is remaining
]
]
Bonus: вот ди Rebmu версии надземной rebmu/args snippet #{DECAFBAD}
где snippet
является:
; modifying
IUgetLOAD"invalid-utf?"MaWT[MiuM][MisMtcTKm]tsA
; copying
IUgetLOAD"invalid-utf?"MaTSrjCT[wt[MiuA][kp copy/partAmKPtcFm AnxM]kpA]
В отличие от других предложенных вариантов, эта версия не возвращает «двоичный!», А «string!» (Так технически, она только расшифровывает Latin 1 в Unicode, но не кодирует это снова для UTF-8). Итак, для перекодировки с латинским-1-UTF-8 просто оставьте вызовы 'to string!'. – earl
* Много * быстрее других: модификация версии 9x, копирование версии 13x. Отличный @rgchris! – giuliolunati
@earl Угадайте, я не обращал внимания. Как вы говорите, в обоих случаях достаточно просто удалить строку 'to string!' И return binary. И спасибо за ссылку :) – rgchris
Ничего не построено в настоящий момент, извините. Вот простая реализация Latin-1 в UTF-8 преобразования, которые я написал и использовал с Rebol 3 некоторое время назад:
latin1-to-utf8: func [
"Transcodes a Latin-1 encoded string to UTF-8"
bin [binary!] "Bytes of Latin-1 data"
] [
to-binary collect [foreach b bin [keep to-char b]]
]
Примечание: этот код оптимизирован для разборчивости и никоим образом не для выполнения , (С точки зрения производительности, это прямо глупо Вы были предупреждены.).
Update: Включенный @ аккуратный BrianH в «Latin-1 байтовые значения соответствуют Unicode кодовых» оптимизации, что делает выше коллапс одноцветный лайнер (и, мягко говоря, глупый одновременно). Все еще. для более оптимизированной версии, касающейся использования памяти, см. хороший ответ BrianH.
@giuliolunati Обратите внимание, что ** to-binary data ** - небольшая оболочка над тем, что, по моему мнению, является лучшим выражением: ** для двоичных данных **. непосредственно к типу данных, вы понимаете, что можете писать такие вещи, как ** (либо условие [строка!] [двоичный!]) данные **. Почему некоторые люди считают, что восклицательный знак, который они используют все время для указания типов, слишком резкий и мне нужна обертка, но некоторые делают. Но если вам когда-нибудь интересно, что-то встроено или нет, вы можете использовать ** source **, например ** source to-binary ** и видеть, что он вызывает TO и не является ** родным! ** или ** действием! ** – HostileFork
Вот версия, которая должна быть немного быстрее и, по крайней мере, использовать меньше памяти.
latin1-to-utf8: func [
"Transcodes a Latin-1 encoded string to UTF-8"
bin [binary!] "Bytes of Latin-1 data"
] [
to binary! head collect/into [
foreach b bin [
keep to char! b
]
] make string! length? bin
]
Он использует символы Latin-1, имеющие одинаковые числовые значения, соответствующие соответствующим кодовым номерам Unicode. Если вы хотите конвертировать из другого набора символов, для которого это не так, вы можете сделать расчет на b
для переназначения символов.
Он использует меньше памяти и быстрее по целому ряду причин:
- Обычно
collect
создает блок. Мы используемcollect/into
и передаем ему строку в качестве цели. Строки используют меньше памяти, чем блоки целых чисел или символов. - Мы предварительно распределяем строку на длину входных данных, что экономит на перераспределениях.
- Мы разрешаем собственный код Rebol преобразовывать символы, а не выполнять свою собственную математику.
- В цикле меньше кода, поэтому он должен работать быстрее.
Этот метод все еще загружает файл в память сразу и по-прежнему создает промежуточное значение для хранения результатов, но по меньшей мере промежуточное значение меньше. Возможно, это позволит вам обрабатывать большие файлы.
Если причиной этого является UTF-8, необходимо обработать файл в виде строки в Rebol, просто пропустите to binary!
и верните строку как есть. Или вы можете просто обрабатывать двоичные исходные данные, просто преобразуйте байты в двоичный файл, используя to char!
на каждом из них, когда вы идете.
Очень аккуратный, +1! Esp. для запоминания соответствия Latin1-to-codepoints. Также хороший пример для полезности значений (capped) integer! как элементы двоичного !. – earl
Найдено, что «append 2x быстрее, чем собирать/в. См. мой ответ. – giuliolunati
latin1-to-utf8: func [
"Transcodes bin as a Latin-1 encoded string to UTF-8"
bin [binary!] "Bytes of Latin-1 data"
/local t
] [
t: make string! length? bin
foreach b bin [append t to char! b ]
t
]
В отличие от другого propo sed, эта версия не возвращает «двоичный!», а «string!» (так технически, она только декодирует латинский 1 в Unicode в памяти, но не кодирует это снова для UTF-8). Чтобы исправить это, вам придется изменить последнюю строку на ** 'на двоичную! T' **. – earl
Sidenote: Я думаю, что в этот день и возраст, переключение самих входных файлов на UTF-8 - лучшая идея ... если это позволяют ограничения вашей ситуации. Это легко сделать с помощью метода @ earl ниже, а затем записать его обратно. Так, например, ** write% myfile.utf8 (latin1-to-utf8 read% myfile.latin1) ** Тогда вам не нужно заботиться о том, как медленно или быстро оно выполняет преобразование, потому что вы делаете это только один раз ... – HostileFork
Полностью согласен с вами. Все мои файлы - utf8. :-) Но некоторые другие не являются :-( – giuliolunati