Ruby 1.8 Iconv UTF-16 в UTF-8 завершается с ошибкой «\ 000» (Iconv :: InvalidCharacter) - PullRequest
3 голосов
/ 30 мая 2011

У меня проблемы с обработкой текстовых файлов табличных данных, сгенерированных на компьютере с Windows.Я работаю в Ruby 1.8.Следующее дает ошибку ("\ 000" (Iconv :: InvalidCharacter)) при обработке ВТОРОЙ строки из файла.Первая строка конвертируется правильно.

require 'iconv'
conv = Iconv.new("UTF-8//IGNORE","UTF-16")
infile = File.open(tabfile, "r")
while (line = infile.gets)
  line = conv.iconv(line.strip)  # FAILS HERE
  puts line
  # DO MORE STUFF HERE
end

Странно то, что она читает и конвертирует первую строку в файле без проблем.У меня есть флаг // IGNORE в конструкторе Iconv - я думал, что это должно было подавить такого рода ошибки.

Я ходил кругами некоторое время.Любой совет будет высоко оценен.

Спасибо!

РЕДАКТИРОВАТЬ: решение Хоббса исправляет это.Спасибо.Просто измените код на:

require 'iconv'
conv = Iconv.new("UTF-8//IGNORE","UTF-16")
infile = File.open(tabfile, "r")
while (line = infile.gets("\x0a\x00"))
  line = conv.iconv(line.strip)  # NO LONGER FAILS HERE
  # DOES MORE STUFF HERE
end

Теперь мне просто нужно найти способ автоматически определить, какой разделитель использовать.

Ответы [ 2 ]

6 голосов
/ 30 мая 2011

Сообщение об ошибке довольно расплывчато, но я думаю, что его огорчает тот факт, что в строке найдено нечетное число байтов, поскольку каждый символ в UTF-16 равен двум (или иногда четырем)байт.И я думаю, что причиной того, что является использование вами gets - строки в вашем файле разделены символом новой строки UTF-16le, который равен 0x0a 0x00, но gets разделяется на (и strip удаляет) 0x0a только.

Для иллюстрации: предположим, что файл содержит

ab
cd

, закодированный в UTF-16le.Это

0x61 0x00 0x62 0x00 0x0a 0x00 0x63 0x00 0x64 0x00 0x0a 0x00
    a         b         \n        c         d         \n

gets читает до первого 0x0a, который strip удаляет, поэтому первое чтение строки равно 0x61 0x00 0x62 0x00, которое iconv с радостью принимает и кодирует в UTF-8 как 0x61 0x62 - «ab».gets затем читает до следующего 0x0a, который strip снова удаляет, поэтому во второй раз line получает 0x00 0x63 0x00 0x64 0x00, и теперь все облажается - мы синхронизированы на один байт, и естьнечетное количество байтов для преобразования, и iconv взрывается, потому что это несовместимо с тем, что вы просили его сделать.

В отсутствие фактического рабочего слоя кодирования / декодирования файлов, я думаю, что вы хотите изменить *Разделитель 1031 * от "\n" ("\x0a") до "\x0a\x00", откажитесь от любого использования strip, поскольку он не является чистым для кодирования, и используйте print вместо puts, чтобы не добавлять лишнюю строку-концы (поскольку вы будете конвертировать уже имеющиеся).

Если вы работаете с файлами Windows, CRLF для Windows в UTF-16le будет "\x0d\x00\x0a\x00".

0 голосов
/ 31 мая 2011

Ответ выше, это хорошо. Вы также можете конвертировать весь файл в UTF-8 перед построчной обработкой, но это может ухудшить потоковую обработку больших файлов.

...