我对一些红宝石行为感到困惑。请查看以下代码:
[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上。
答案 0 :(得分: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
,因为代码点0
到127
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
。
答案 1 :(得分:1)
在Ruby 1.9中,默认的源文件编码为US-ASCII
。从Ruby 2.0开始,默认编码已更改为UTF-8
。像"\x80"
这样的字符串文字总是使用包含它们的源文件的编码进行编码。
但是,[128].pack("C")
的编码为ASCII-8BIT
。
所以[128].pack("C") == "\x80"
在Ruby 2.0中是false
而在Ruby 1.9中是true
将#coding:some_encoding
放在源文件的第一行(或者只是在shebang之后)可以更改默认的源代码编码。
#coding:ascii
puts([128].pack("C") == "\x80")
在Ruby 2.0中输出true
。