我对某些 ruby 行为感到困惑。看下面的代码:

[127].pack("C") == "\x7f"   # => true

这是有道理的。现在:
[128].pack("C")             # => "\x80"
"\x80"                      # => "\x80"
[128].pack("C") == "\x80"   # => false

pack option "C"代表8-bit unsigned (unsigned char),应该可以存储128的值。而且两个字符串都打印相同的东西,所以为什么它们不相等?这与编码内容有关吗?

我使用的是ruby 2.0.0p247。

最佳答案

这是错误的,因为编码不同:

[128].pack("C").encoding
#=> #<Encoding:ASCII-8BIT>
"\x80".encoding
#=> #<Encoding:UTF-8>

(使用ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux])

在ruby 2.0中,字符串的默认编码为UTF-8,但是pack以某种方式返回ASCII 8位编码的字符串。

为什么[127].pack('C') == "\x79"是true?

但是,[127].pack('C') == "\x79"true,因为对于代码点0127,ASCII和UTF-8不会不同。这是通过ruby的字符串比较来考虑的(请看the rubinius source code):
def ==(other)
  [...]

  return false unless @num_bytes == other.bytesize
  return false unless Encoding.compatible?(self, other)
  return @data.compare_bytes(other.__data__, @num_bytes, other.bytesize) == 0
end

mri c-source是相似的,但是更难理解。

我们观察到,比较检查了兼容的编码。让我们尝试一下:
Encoding.compatible?([127].pack("C"), "\x79") #=> #<Encoding:ASCII-8BIT>
Encoding.compatible?([128].pack("C"), "\x80") #=> nil

我们看到,从代码点128开始,即使两个字符串都由相同的字节组成,比较也返回false

10-04 22:00
查看更多