2014-02-12 8 views
4

Я хочу использовать Rebol 3 для чтения файла в Latin1 и преобразования его в UTF-8. Есть ли встроенная функция, которую я могу использовать, или какая-то внешняя библиотека? Где я могу это найти?Выполнение преобразования кодировки файла с помощью Rebol 3

+0

Sidenote: Я думаю, что в этот день и возраст, переключение самих входных файлов на UTF-8 - лучшая идея ... если это позволяют ограничения вашей ситуации. Это легко сделать с помощью метода @ earl ниже, а затем записать его обратно. Так, например, ** write% myfile.utf8 (latin1-to-utf8 read% myfile.latin1) ** Тогда вам не нужно заботиться о том, как медленно или быстро оно выполняет преобразование, потому что вы делаете это только один раз ... – HostileFork

+0

Полностью согласен с вами. Все мои файлы - utf8. :-) Но некоторые другие не являются :-( – giuliolunati

ответ

4

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] 
+1

В отличие от других предложенных вариантов, эта версия не возвращает «двоичный!», А «string!» (Так технически, она только расшифровывает Latin 1 в Unicode, но не кодирует это снова для UTF-8). Итак, для перекодировки с латинским-1-UTF-8 просто оставьте вызовы 'to string!'. – earl

+1

* Много * быстрее других: модификация версии 9x, копирование версии 13x. Отличный @rgchris! – giuliolunati

+0

@earl Угадайте, я не обращал внимания. Как вы говорите, в обоих случаях достаточно просто удалить строку 'to string!' И return binary. И спасибо за ссылку :) – rgchris

3

Ничего не построено в настоящий момент, извините. Вот простая реализация 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.

+0

@giuliolunati Обратите внимание, что ** to-binary data ** - небольшая оболочка над тем, что, по моему мнению, является лучшим выражением: ** для двоичных данных **. непосредственно к типу данных, вы понимаете, что можете писать такие вещи, как ** (либо условие [строка!] [двоичный!]) данные **. Почему некоторые люди считают, что восклицательный знак, который они используют все время для указания типов, слишком резкий и мне нужна обертка, но некоторые делают. Но если вам когда-нибудь интересно, что-то встроено или нет, вы можете использовать ** source **, например ** source to-binary ** и видеть, что он вызывает TO и не является ** родным! ** или ** действием! ** – HostileFork

4

Вот версия, которая должна быть немного быстрее и, по крайней мере, использовать меньше памяти.

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! на каждом из них, когда вы идете.

+0

Очень аккуратный, +1! Esp. для запоминания соответствия Latin1-to-codepoints. Также хороший пример для полезности значений (capped) integer! как элементы двоичного !. – earl

+0

Найдено, что «append 2x быстрее, чем собирать/в. См. мой ответ. – giuliolunati

1
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 
] 
+0

В отличие от другого propo sed, эта версия не возвращает «двоичный!», а «string!» (так технически, она только декодирует латинский 1 в Unicode в памяти, но не кодирует это снова для UTF-8). Чтобы исправить это, вам придется изменить последнюю строку на ** 'на двоичную! T' **. – earl

 Смежные вопросы

  • Нет связанных вопросов^_^