Почему в Ruby 1.9 две строки с одинаковыми байтами и кодировкой не идентичны? - PullRequest
4 голосов
/ 21 ноября 2010

В Ruby 1.9.2 я нашел способ создать две строки, которые имеют одинаковые байты, одинаковую кодировку и равны, но имеют разные length и разные символы, возвращаемые [].

Это ошибка? Если это не ошибка, то я хотел бы полностью понять это. Какая информация хранится в Ruby 1.9.2 Строковых объектах, которые позволяют этим двум строкам вести себя по-разному?

Ниже приведен код, который воспроизводит это поведение. Комментарии, начинающиеся с #=>, показывают, какой вывод я получаю из этого сценария, а слова в скобках говорят о моем суждении об этом выводе.

#!/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]

Ответы [ 3 ]

8 голосов
/ 22 ноября 2010

Это ошибка Руби и исправлено r29848 .

2 голосов
/ 22 ноября 2010

Матц упомянул этот вопрос через Twitter:

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

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

"Трудно определить, как ошибку, но нельзя оставить ее как есть. Я бы предпочел исправить эту проблему."

1 голос
/ 21 ноября 2010

Я думаю, что проблема в кодировке строки. Ознакомьтесь с Shades of Grey Джеймса Грея: статья Ruby 1.9 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"
...