我认为Ruby UTF-16编码

时间:2015-10-05 23:00:40

标签: ruby windows encoding popen3 utf-16le

我有一个在Windows上运行的Ruby程序,它使用Open3调用shell命令(已知输出UTF-16):

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

如果对UTF_16LE的force_encoding不起作用并抛出异常,我只需保存字节,将其编码为JSON字符串并将其编码为UTF_8。

嗯......异常被抛出,我在rescue子句中捕获了输出字节数组。它看起来像这样:

[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]转换为“dog”或[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 个答案:

答案 0 :(得分:3)

回答关于字节的第一个问题,看看数组中的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>

这对像'dog'这样的字符串有预期的效果,因为UTF-8向后兼容ASCII-8BIT,这意味着只使用ASCII-8BIT字符的字符串将以UTF-8工作。但是对于在UTF-8中使用超过1个字节的字符,如'€',它们在ASCII中无法识别。所以,为了回答你的问题,你需要做的是对字符串强制进行适当的编码,如下所示:

"कुत्रा".bytes.map{|c| c.chr}.join("").force_encoding('UTF-8') #=> "कुत्रा"

希望有所帮助

答案 1 :(得分:1)

  

有没有办法以编程方式将[100,111,103]转换为&#34; dog&#34;?

Array#pack

pry(main)> "dog".bytes.pack('c*')
=> "dog"

对于其他字母,请尝试相同或&#34;कुत्रा&#34;。bytes.pack(&#39; U *&#39;)。 我不能在我的电脑中使用那些马拉地语(呃,这也意味着“狗”等)

  

如何将这个奇怪的字符串或字节序列转换为更有意义的&#34;कुत्रा&#34; ?

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"