将字符串(表示UTF-8十六进制)转换为字符串

时间:2015-04-25 06:45:58

标签: ruby utf-8 string-decoding

我有一个UTF-8十六进制字符串,如下所示:

s = "0059006F007500720020006300720065006400690074002000680061007300200067006F006E0065002000620065006C006F00770020003500200064006F006C006C006100720073002E00200049006600200079006F00750020006800610076006500200061006E0020004100640064002D004F006E0020006F007200200042006F006E0075007300200079006F007500720020007200650073006F00750072006300650073002000770069006C006C00200077006F0072006B00200075006E00740069006C0020006500780068006100750073007400650064002E00200054006F00200074006F00700020007500700020006E006F007700200076006900730069007400200076006F006400610066006F006E0065002E0063006F002E006E007A002F0074006F007000750070"

我想将其转换为实际的UTF-8字符串。它应该是:

  

您的信用额度已低于5美元。如果您有附加组件或奖励,您的资源将一直有效,直到用尽为止。现在请访问vodafone.co.nz/topup

这有效:

s.scan(/.{4}/).map { |a| [a.hex].pack('U') }.join

但我想知道是否有更好的方法:我是否应该使用Encoding#convert

3 个答案:

答案 0 :(得分:4)

额外00表示该字符串实际上是UTF-16字符串的十六进制表示,而不是UTF-8。假设您需要执行以获取UTF-8字符串的步骤首先将字符串转换为十六进制数字表示的实际字节(Array#pack可用于此),其次将其标记为使用force_encoding(看起来像UTF-16BE)进行适当的编码,最后使用encode将其转换为UTF-8:

[s].pack('H*').force_encoding('utf-16be').encode('utf-8')

答案 1 :(得分:1)

我认为字符串中有额外的空字符(它有效,但很浪费),但您可以尝试:

[s].pack('H*').force_encoding('utf-8')

虽然,似乎"您的信用额度已低于5美元" ...

字符串打印puts,但是当转换字符串时,我无法读取终端上的所有unicode字符。

答案 2 :(得分:1)

如果您打算在其他奇怪编码的字符串上使用它,您可以取消填充前导字节:

[s.gsub(/..(..)/,'\1')].pack('H*')

或者使用它们:

s.gsub(/..../){|p|p.hex.chr}

如果你想使用Encoding :: Converter

ec = Encoding::Converter.new('UTF-16BE','UTF-8')     # save converter for reuse
ec.convert( [s].pack('H*') )                         # or:  ec.convert [s].pack'H*'