为什么 Ruby 将整数转换为八进制转义字符串而不是十六进制转义字符串?

Why does Ruby convert integer to octal-escaped string instead of hex-escaped one?

我需要:

"ff".hex.chr #=> "\xff"

但我得到的是:

"ff".hex.chr #=> "7"

我的错误在哪里?什么不见​​了?环境是HBase 0.98.6 shell,好像是基于JRuby 1.6.8 console.

"\xff""7"是同一数据的不同表示:

  • "\xff" 是十六进制,是较新的 Ruby 版本的典型值。
  • "7" 是八进制,是旧 Ruby 版本的典型值。

您可以看到相同的数字如何产生不同的字符串:

printf("%o",255) #=> "377"
printf("%x",255) #=> "ff"

默认表示通常是由于您的控制台设置和 Ruby 版本。

一般来说,即使在相同的 Ruby 版本上,也不要依赖 String#inspect 来产生一致的表示。如果您使用一些特殊字符,您可以看到实际效果:

"[=11=]7" #=> "\a"

String#inspect 方法已将表示形式更改为既不是八进制也不是十六进制。

如果您要输出到需要特定格式的系统,您可以明确:

printf("\x%x", 255) #=> \xff  # lower case
printf("\x%X", 255) #=> \xFF  # upper case

您也可以尝试packunpack方法:

["ff"].pack("H*") #=> "\xFF"

如果你的字符串总是十六进制数字,而你想要的输出只是在每两个字符前插入“\x”,那么有一个快速的解决方案:

print "a1b2c3".gsub(/../){"\x#{$&}"}
#=> \xa1\xb2\xc3

Ruby 字符串表示以及如何使用不可打印字符的快速介绍在 Safari Books Ruby Cookbook

经验教训:

  • 实际上八位字节没有任何功能问题。只是表示(感谢所有评论和答案)。内部字符串内容相同。
  • 是的,在 Ruby 1.8 中有格式为“%03o”的 String#inspect。是的,HBase 0.98.6 将此 Ruby 版本用于 JRuby 1.6.8。就我而言,这不容易解决。
  • 检查与实际结果无关,所以我使用了 Hbase Bytes class 并为需要查看预期键表示的人准备了特殊的 printer

这是实际解决我所有任务的代码,包括需要的输出:

# Convert binary string to hex digits.
def bin_to_hex(s)
  s.each_byte.map { |b| b.to_s(16).rjust(2, '0') }.join
end

# Convers hex string to binary string.
def hex_to_bin(s)
  s.scan(/../).map { |x| x.hex.chr }.join
end

# HBase special 'convert and print' routine to get hex digits, process them and print.
def print_hex_to_bin(s)
  Kernel.print "\"" + Bytes.toStringBinary(s.scan(/../).map { |x| x.hex.chr }.join.to_java_bytes) + "\"\n"
end

主要基于http://anthonylewis.com/2011/02/09/to-hex-and-back-with-ruby/

组成