6

我对一些红宝石行为感到困惑。看下面的代码:

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

这是有道理的。现在:

[128].pack("C")             # => "\x80"
"\x80"                      # => "\x80"
[128].pack("C") == "\x80"   # => false

打包选项“C”代表,8-bit unsigned (unsigned char)应该可以存储128. 两个字符串也打印相同的东西,为什么它们不相等?这与编码有关吗?

我在 ruby​​ 2.0.0p247 上。

4

2 回答 2

5

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

[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"真的呢?

但是,[127].pack('C') == "\x79"true,因为对于 ASCII 和 UTF-8 的码点来说0没有127区别。ruby 的字符串比较考虑了这一点(查看rubinius 源代码):

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即使两个字符串由相同的字节组成,比较也会返回。

于 2013-11-14T12:43:07.260 回答
1

在 Ruby 1.9 中,默认的源文件编码是US-ASCII. 从 Ruby 2.0 开始,默认编码已更改为UTF-8. 像这样的字符串文字"\x80"总是使用包含它们的源文件的编码进行编码。

但是,编码[128].pack("C")ASCII-8BIT.

在 Ruby 2.0和 Ruby 1.9 中[128].pack("C") == "\x80"也是如此falsetrue

放入#coding:some_encoding源文件的第一行(或在 shebang 之后)可以更改默认的源代码编码。

#coding:ascii
puts([128].pack("C") == "\x80")

Ruby 2.0 中的输出true也是如此。

于 2013-11-14T12:56:10.827 回答