Я хочу использовать Rebol 3 для чтения файла на Latin1 и преобразования его в UTF-8. Есть ли встроенная функция, которую я могу использовать, или какая-то внешняя библиотека? Где я могу найти это?
Выполните преобразование кодировки файлов с помощью Rebol 3
Ответы (4)
В Rebol есть функция invalid-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
]
]
Бонус: вот небольшая 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]
binary!
, а string!
(так что технически она только декодирует латиницу 1 в Unicode, но не кодирует ее снова в UTF-8). Поэтому для истинного перекодирования Latin-1 в UTF-8 просто не используйте вызовы to string!
.
- person earl; 05.04.2014
to string!
и вернуть двоичный файл. И спасибо за ссылку :)
- person rgchris; 05.04.2014
Вот версия, которая должна быть немного быстрее и, по крайней мере, использовать меньше памяти.
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!
для каждого из них по мере продвижения.
На данный момент ничего не встроено, извините. Вот простая реализация преобразования 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]]
]
Примечание. Этот код оптимизирован для удобочитаемости и ни в коем случае для производительности. (С точки зрения производительности это совершенно глупо. Вас предупредили.)
Обновление: Включена оптимизация @BrianH "байтовые значения Latin-1 соответствуют кодовым точкам Unicode", которая сводит вышеописанное к однострочному (и в то же время немного менее глупому). Еще. более оптимизированную версию использования памяти см. в хорошем ответе @BrianH.
binary!
, а string!
(так что технически она только декодирует латиницу 1 в Unicode в памяти, но не кодирует ее снова в UTF-8). Чтобы это исправить, вам нужно изменить последнюю строку на to binary! t
.
- person earl; 05.04.2014