2015-11-14 15 views
6

Ich habe vor kurzem mit der Codierung in Ruby arbeiten, und bin durch ein Verhalten verwirrt.String Encoding in Ruby

Ich verwende 2.2.3p173 und bin zeigt folgendes:

__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> 

Was in Codierungen die Ursache für diese Diskrepanz ist?

Antwort

4

Schöner Fund!

Die kurze Antwort ist, es ist völlig willkürlich und es hängt davon ab, wie Ruby intern die Zeichenfolgen erstellt, die zurückgegeben werden.

Es gibt eine ganze Reihe von internen C-Funktionen, die leere Zeichenfolgen oder Literalzeichenfolgen mit US-ASCII-Codierung erstellen: rb_usascii_str_new und ähnlich. Sie werden häufig verwendet, um Strings zu konstruieren, indem kleinere Fragmente von Strings angehängt werden. Fast jeder tut to_s Methode dies:

[].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> 

Warum also nicht Object.new.to_s? Der Schlüssel hier ist, dass Object#to_s die Fallback to_s Methode für jede Klasse ist, so um es generisch-noch-informativen sie kodierten es den Wert des internen Zeiger des Objekts ausgeben. Der einfachste Weg dazu ist sprintf und der %p Spezifizierer. ABER Wer Ruby sprintf wrapper rb_sprintf codiert wurde faul und nur die Codierung auf NULL, die auf ASCII-8BIT fällt. So im Allgemeinen alles, was eine formatierte Zeichenfolge zurückgibt, wird diese Codierung hat:

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

Wie für Strings durch ein Skript definiert ist, erhalten diejenigen, die die Standard-Kodierung UTF-8 als man erwarten würde.

1

Object in C definiert, wenn Sie versuchen, die folgenden:

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

Ich habe nicht viel in Ruby-Quellcode graben, aber es looks wie harcoded ist die Codierung (rb_usascii_str_new2) für to_s