2015-11-14 3 views
6

Недавно я начал работать с кодировкой в ​​Ruby и смущен каким-то поведением.Кодировка строк в Ruby

Я использую 2.2.3p173 и я показываю следующее:

__ENCODING__    #=> #<Encoding:UTF-8> Default encoding in 2.2.3 

"my_string".encoding  #=> #<Encoding:UTF-8> 
Object.to_s.encoding  #=> #<Encoding:US-ASCII> 
Object.new.to_s.encoding #=> #<Encoding:ASCII-8BIT> 

Что является причиной этого несоответствия в кодировках?

ответ

4

Хорошая находка!

Короткий ответ - это полностью произвольно, и это зависит от того, как Ruby внутренне создает строки, которые возвращаются.

Существует целый ряд внутренних функций C, которые строят пустые строки или литералы с кодировкой US-ASCII: rb_usascii_str_new и тому подобное. Они часто используются для построения строк путем добавления небольших фрагментов строк. Почти каждый to_s метод делает это:

[].to_s.encoding 
#<Encoding:US-ASCII> 
{}.to_s.encoding 
#<Encoding:US-ASCII> 
$/.to_s.encoding 
#<Encoding:US-ASCII> 
1.to_s.encoding 
#<Encoding:US-ASCII> 
true.to_s.encoding 
#<Encoding:US-ASCII> 
Object.to_s.encoding 
#<Encoding:US-ASCII> 

Так почему бы не Object.new.to_s? Ключ здесь состоит в том, что Object#to_s - это метод возврата to_s для каждого класса, поэтому, чтобы сделать его общим, но все же информативным, он закодировал его для вывода значения внутреннего указателя объекта. Самый простой способ сделать это - sprintf и спецификатор %p. BUT кто-то закодированный Ruby's sprintf обертка rb_sprintf получил ленивый и просто установил кодировку в NULL, которая возвращается к ASCII-8BIT. Так что в целом все, что возвращает отформатированную строку будет иметь эту кодировку:

Object.new.to_s 
#<Encoding:ASCII-8BIT> 
nil.sort rescue $!.to_s.encoding 
#<Encoding:ASCII-8BIT> 
[].each.to_s.encoding 
#<Encoding:ASCII-8BIT> 

Что касается строк, определенных с помощью сценария, те получают кодировку UTF-8 по умолчанию, как можно было бы ожидать.

1

Object определяются в C , если вы выполните следующие действия:

String(123456).encoding #=> #<Encoding:ASCII-8BIT> 
"123456".encoding  #=> #<Encoding:UTF-8> 

я не копал много в исходном коде рубинового но looks нравится это harcoded кодировки (rb_usascii_str_new2) для to_s

Смежные вопросы