【问题标题】:Why are two strings with same bytes and encoding not identical in Ruby 1.9?为什么在 Ruby 1.9 中两个具有相同字节和编码的字符串不相同?
【发布时间】:2010-11-21 06:58:51
【问题描述】:

在 Ruby 1.9.2 中,我找到了一种方法来制作两个字符串,它们具有相同的字节、相同的编码并且相等,但它们具有不同的 length[] 返回的不同字符。

这是一个错误吗?如果它不是错误,那么我想完全理解它。 Ruby 1.9.2 String 对象中存储了什么样的信息,允许这两个字符串表现不同?

以下是重现此行为的代码。以#=> 开头的 cmets 向您展示了我从该脚本中得到了什么输出,括号中的文字告诉您我对该输出的判断。

#!/usr/bin/ruby1.9
# coding: utf-8
string1 = "\xC2\xA2"       # A well-behaved string with one character (¢)
string2 = "".concat(0xA2)  # A bizarre string very similar to string1.
p    string1.bytes.to_a    #=> [194, 162]  (good)
p    string2.bytes.to_a    #=> [194, 162]  (good)
puts string1.encoding.name #=> UTF-8  (good)
puts string2.encoding.name #=> UTF-8  (good)
puts string1 == string2    #=> true   (good)
puts string1.length        #=> 1      (good)
puts string2.length        #=> 2      (weird!)
p    string1[0]            #=> "¢"    (good)
p    string2[0]            #=> "\xC2" (weird!)

我正在运行 Ubuntu 并从源代码编译 Ruby。我的 Ruby 版本是:

ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]

【问题讨论】:

  • p string2.bytes.to_a 显示结果[194, 162] ??那不应该!
  • 实际上,Zabba,这是预期的结果,因为 194,162 是分字符 ¢(代码点 0xA2)的 UTF-8 编码。显然,如果您将一个整数传递给 concat,它会将一个具有该值的字符添加到您的字符串中。请参阅 Wikipedia aobut UTF-8 中的此表。他们以第二行中的分字符为例:en.wikipedia.org/wiki/UTF-8#Description

标签: ruby string encoding ruby-1.9


【解决方案1】:

这是 Ruby 的错误,已修复 r29848

【讨论】:

【解决方案2】:

Matz 在 Twitter 上提到了这个问题:

http://twitter.com/matz_translator/status/6597021662187520

http://twitter.com/matz_translator/status/6597055132733440

“很难确定它是一个错误,但是,让它保持原样是不可接受的。我更愿意修复这个问题。”

【讨论】:

    【解决方案3】:

    我认为问题在于字符串的编码。查看 James Grey 的 Shades of Gray: Ruby 1.9's String 关于 Unicode 编码的文章。


    其他奇怪的行为:

    # coding: utf-8
    
    string1 = "\xC2\xA2"       
    string2 = "".concat(0xA2)  
    string3 = 0xC2.chr + 0xA2.chr
    
    string1.bytes.to_a    # => [194, 162]
    string2.bytes.to_a    # => [194, 162]
    string3.bytes.to_a    # => [194, 162]
    
    string1.encoding.name # => "UTF-8"
    string2.encoding.name # => "UTF-8"
    string3.encoding.name # => "ASCII-8BIT"
    
    string1 == string2    # => true
    string1 == string3    # => false
    string2 == string3    # => true
    
    string1.length        # => 1
    string2.length        # => 2
    string3.length        # => 2
    
    string1[0]            # => "¢"
    string2[0]            # => "\xC2"
    string3[0]            # => "\xC2"
    

    string3.unpack('C*') # => [194, 162]
    string4 = string3.unpack('C*').pack('C*') # => "\xC2\xA2"
    string4.encoding.name # => "ASCII-8BIT"
    string4.force_encoding('UTF-8') # => "¢"
    
    string3.force_encoding('UTF-8') # => "¢"
    string3.encoding.name # => "UTF-8"
    

    【讨论】:

    • 我今晚早些时候发现了那篇文章并阅读了大部分内容,但没有找到答案。请注意,string1 和 string2 都具有相同的编码,即 UTF-8。要么我在 Ruby 中发现了一个错误,要么该文章对 Ruby 1.9 的描述不完整。这篇文章声称“在 Ruby 1.9 中,字符串现在是编码数据的集合。这意味着它既是原始字节,也是关于如何解释这些字节的附加编码信息。”但是这两个字符串具有相同的字节和相同的编码,那么为什么它们的行为不同呢?字符串肯定还有其他重要的属性。
    • 我倾向于认为它是一个错误。将concat 与整数一起使用对我来说并不直观。我正在搞一些额外的测试,看看我能挖掘出什么。
    • 我认为这是 concat 中的一个错误。
    猜你喜欢
    • 1970-01-01
    • 2012-07-19
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多