luc*_*nte 6 ruby string encoding
我对一些红宝石行为感到困惑.看下面的代码:
[127].pack("C") == "\x7f" # => true
Run Code Online (Sandbox Code Playgroud)
这是有道理的.现在:
[128].pack("C") # => "\x80"
"\x80" # => "\x80"
[128].pack("C") == "\x80" # => false
Run Code Online (Sandbox Code Playgroud)
该组选"C"表示8-bit unsigned (unsigned char),这应该是罚款存储值128.两个字符串也打印相同的东西,为什么它们不相等?这与编码内容有关吗?
我在ruby 2.0.0p247上.
这是错误的,因为编码不同:
[128].pack("C").encoding
#=> #<Encoding:ASCII-8BIT>
"\x80".encoding
#=> #<Encoding:UTF-8>
Run Code Online (Sandbox Code Playgroud)
(使用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到127ASCII和UTF-8没有区别.这是通过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
Run Code Online (Sandbox Code Playgroud)
该MRI c源极相似,但更难理解.
我们观察到,比较检查兼容的编码.我们试试看:
Encoding.compatible?([127].pack("C"), "\x79") #=> #<Encoding:ASCII-8BIT>
Encoding.compatible?([128].pack("C"), "\x80") #=> nil
Run Code Online (Sandbox Code Playgroud)
我们看到,从代码点128开始,false即使两个字符串都由相同的字节组成,比较也会返回.