Ruby UTF-16 кодировка я думаю
У меня есть программа Ruby, работающая в Windows, которая вызывает команду оболочки (которая, как известно, выводит UTF-16), используя Open3:
attrs={}
attrs[:stdout], attrs[:stderr], status = Open3.capture3(command)
unless attrs[:stderr].nil?
begin
attrs[:stderr].force_encoding(Encoding::UTF_16LE).encode!(Encoding::UTF_8)
rescue => e
attrs[:stderr] = attrs[:stderr].bytes.to_json.encode!(Encoding::UTF_8)
end
end
Если force_encoding в UTF_16LE не работает и выдает исключение, я просто сохраняю байты, кодирую его как строку JSON и кодирую как UTF_8.
Ну... исключение было выдано, и я поймал выходной массив байтов в предложении спасения. Это выглядит так:
[10,84,104,105,115,32,97,112,112,108,105,99,97,116,105,111,110,32,104,97,115,32,114,101,113,117,101,115,116,101,100,32,116,104,101,32,82,117,110,116,105,109,101,32,116,111,32,116,101,114,109,105,110,97,116,101,32,105,116,32,105,110,32,97,110,32,117,110,117,115,117,97,108,32,119,97,121,46,10,80,108,101,97,115,101,32,99,111,110,116,97,99,116,32,116,104,101,32,97,112,112,108,105,99,97,116,105,111,110,39,115,32,115,117,112,112,111,114,116,32,116,101,97,109,32,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111,110,46,10]
Как я могу преобразовать его обратно в текст в каком-то формате. например, если я делаю:
irb> "dog".bytes
=> [100, 111, 103]
irb> "कुत्रा".bytes
=> [224, 164, 149, 224, 165, 129, 224, 164, 164, 224, 165, 141, 224, 164, 176, 224, 164, 190]
Есть ли способ программно преобразовать [100, 111, 103] в "собаку" или [224, 164, 149, 224, 165, 129, 224, 164, 164, 224, 165, 141, 224, 164, 176, 224, 164, 190] вернуться к "कुत्रा"? И есть ли способ выяснить, что означает мой выходной массив байтов?
------------------------- ОБНОВИТЬ ------------------------ ---
Я немного покопался, но это заняло некоторое время, потому что "декодировать" - это не вещь. Тем не менее, я сделал следующее с массивом, который содержал в сообщении переменной:
message.map{|c| c.chr}.join("")
=> "\nThis application has requested the Runtime to terminate it in an unusual way.\nPlease contact the application's support team for more information.\n"
Так что моя проблема решена тем, что сообщение об ошибке отсутствует в UTF-16LE.
Однако, когда я сделал это, я получил следующий результат:
irb> "कुत्रा".bytes.map{|c| c.chr}.join("")
=> "\xE0\xA4\x95\xE0\xA5\x81\xE0\xA4\xA4\xE0\xA5\x8D\xE0\xA4\xB0\xE0\xA4\xBE"
Как мне преобразовать эту странно выглядящую строку или последовательность байтов в более значимое "कुत्रा"?
2 ответа
Отвечая на ваш первый вопрос о байтах, взгляните на метод Pack в массиве: docs.
[100, 111, 103].pack('U*') # Returns 'dog'.
Форматирование 'U*' пытается найти в байтовом массиве как можно больше символов UTF8.
Если вы используете этот метод в своем сообщении об ошибке, вы получите:
"\nThis application has requested the Runtime to terminate it in an unusual way.\nPlease contact the application's support team for more information.\n"
------------------------- ОБНОВИТЬ ------------------------ ---
Просто заметил, что вы разобрались с первой частью и добавили новый вопрос.
Как мне преобразовать эту странно выглядящую строку или последовательность байтов в более значимое "कुत्रा"?
Когда вы выполняете "string".bytes.map{|c| c.chr}.join("")
байты в новой строке совпадают, но кодировка теряется. Это можно увидеть здесь:
s = "dog"
s.encoding #=> #<Encoding:UTF-8>
s = "dog".bytes.map{|c| c.chr}.join("") #=> "dog"
s.encoding #=> #<Encoding:US-ASCII>
Это имеет ожидаемый эффект со строками типа "собака", поскольку UTF-8 обратно совместим с ASCII-8BIT, это означает, что строка, использующая только символы ASCII-8BIT, будет работать в UTF-8. Но с символами, которые используют более 1 байта в UTF-8, например, '€', они не распознаются в ASCII. Итак, чтобы ответить на ваш вопрос, вам нужно наложить соответствующую кодировку на строку, например так:
"कुत्रा".bytes.map{|c| c.chr}.join("").force_encoding('UTF-8') #=> "कुत्रा"
Надеюсь, поможет
Есть ли способ программно преобразовать [100, 111, 103] в "собаку"?
pry(main)> "dog".bytes.pack('c*')
=> "dog"
Для других букв попробуйте то же самое или "कुत्रा". Bytes.pack('U*'). Я не могу использовать эти маратхи (Эхх, это также означает "собака", смеется) в моем компьютере.
Как мне преобразовать эту странно выглядящую строку или последовательность байтов в более значимое "कुत्रा"?
pry(main)> p "कुत्रा".bytes.map{|c| c.chr}.join("")
=> "\xE0\xA4\x95\xE0\xA5\x81\xE0\xA4\xA4\xE0\xA5\x8D\xE0\xA4\xB0\xE0\xA4\xBE"
pry(main)> puts "कुत्रा".bytes.map{|c| c.chr}.join("")
=> कुत्रा
Что в основном:
puts "\xE0\xA4\x95\xE0\xA5\x81\xE0\xA4\xA4\xE0\xA5\x8D\xE0\xA4\xB0\xE0\xA4\xBE"