2015-10-05 80 views
0

我有运行在Windows Ruby程序它调用一个外壳命令(这是众所周知的输出UTF-16)使用Open3:红宝石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 

如果force_encoding到UTF_16LE没有按” t工作,并抛出一个异常,我简单地保存字节,将其编码为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]以 “狗” 或[224,164,149,224,165,129,224,164,164,224 ,165,141,224,164,176,224,164,190]回到“कुत्रा”?有没有一种方法来找出我的输出数组字节的含义?

------------------------- UPDATE -------------------- -------

我挖了一下,但花了一段时间,因为“解码”不是一回事。然而,我与我的变量保持在阵列下面消息

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" 

如何转换这种奇怪的看着字符串或字节序列到更有意义的“कुत्रा”?

+0

难道我回答你的问题,更新的问题? – pedros

回答

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> 

这与像“狗”串预期的效果,因为UTF-8是ASCII-8BIT向后兼容,这意味着仅使用ASCII-8BIT字符将工作该字符串在UTF-8。但是对于UTF-8中使用多于1个字节的字符,如'€',它们不能用ASCII识别。因此,要回答你的问题,你需要做的是迫使相应的编码串上,像这样:

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

希望它可以帮助

+0

值得一提 - 'U'表示UTF- * 8 *,而不是UTF-16/UCS2。如果你实际上在处理UTF-16,那么类似这样的东西可能是合适的(未经测试):'bytes.map(&:chr).join.force_encoding(Encoding :: UTF_16)'。 – Linuxios

1

有没有一种方法以编程方式转换[100, 111,103]到“狗”?

Array#pack

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

对于其他字母,尝试同样的或 “कुत्रा”。bytes.pack( 'U *')。 我不能使用那些马拉(EHH这也意味着“狗”笑)在我的电脑

如何转换这种奇怪的看着字符串或字节序列到更有意义的“कुत्रा”?

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"