作者:hooopo 时间:2011年12月07日 00:32 评论(4)
Ruby1.9的字符串编码改动非常大。在Ruby1.8,每个字符串都是字节序列,没有字符的概念。唯一一个和字符编码有关的$KCODE可以指定全局的编码。 但是$KCODE对字符串编码的改变很小,因为$KCODE只做了这样几件事:
让ruby解析器按照$KCODE的编码方式解析源代码
让inspect方法按$KCODE的编码方式显示字符
让正则按照$KCODE的编码方式匹配
影响inspect
ree-1.8.7-2011.03 :016 > $KCODE = "a"
=> "a"
ree-1.8.7-2011.03 :017 > p "Résumé"
"R\303\251sum\303\251"
=> nil
ree-1.8.7-2011.03 :018 > p "你好"
"\344\275\240\345\245\275"
=> nil
ree-1.8.7-2011.03 :019 > $KCODE = "U"
=> "U"
ree-1.8.7-2011.03 :020 > p "你好"
"你好"
=> nil
ree-1.8.7-2011.03 :021 > p "Résumé"
"Résumé"
=> nil
影响正则:
ree-1.8.7-2011.03 :027 > $KCODE = "a"
=> "a"
ree-1.8.7-2011.03 :028 > "你好".scan(/./)
=> ["\344", "\275", "\240", "\345", "\245", "\275"]
ree-1.8.7-2011.03 :030 > $KCODE = "U"
=> "U"
ree-1.8.7-2011.03 :031 > "你好".scan(/./)
=> ["你", "好"]
并且,$KCODE是一个全局的变量,它对所有文件产生作用,这在你的程序里引入了第三方库,时候会遇到麻烦。
Ruby1.9对字符编码的控制分的很细:
源文件编码
外编码
内编码
[h1]源文件编码[/h1]
Ruby1.9里,所有的字符串字面量都由字符序列+编码标识组成。 可以通过一个magick comment(# encoding: utf-8)来声明源代码里的字符串字面量的编码标识。这个comment针对每个文件起作用,不像1.8的$KCODE是在全局起作用。可以通过force_encoding方法来改变字符的编码标识(force_encoding并未转换编码,只改变标识)
# encoding: GBK
puts ENCODING #=> GBK
puts "".encoding #=> GBK
str = "你好".force_encoding "UTF-8"
puts str.encoding # => UTF-8
虽然force_encoding只改变了字符的编码标识,没有改变字节序列,但是,随着字符串的编码标识的改变,字符串的一些行为也跟着改变,比如inspect和each_char:
ruby-1.9.3-rc1 :017 > str = "你好"
=> "你好"
ruby-1.9.3-rc1 :018 > p str.encoding
#<Encoding:UTF-8>
=> #<Encoding:UTF-8>
ruby-1.9.3-rc1 :019 > str.each_char{|x| p "#{x}—> #{x.bytesize}"}
"你—> 3"
"好—> 3"
=> "你好"
ruby-1.9.3-rc1 :020 > str.force_encoding "GBK"
=> "\x{E4BD}\x{A0E5}\x{A5BD}"
ruby-1.9.3-rc1 :021 > str.each_char{|x| p "#{x}—> #{x.bytesize}"}
"\x{E4BD}—> 2"
"\x{A0E5}—> 2"
"\x{A5BD}—> 2"
=> "\x{E4BD}\x{A0E5}\x{A5BD}"
ruby-1.9.3-rc1 :022 >
[h1]外部编码[/h1] 字符串的来源可能有两种,一种是前面提到的源文件,另外一种是从外部IO读取到的。 对于第一种我们可以直接通过magick comment来设置字符串的默认编码标识。而从外部IO读取到的字符编码标识是通过IO对象的external_encoding和internal_encoding来设置的。
hooopohooopo</span><span class="symbol">:~</span>/rubyist<span class="error">$</span> cat show_external_encoding.rb
open(<span class="predefined-constant">__FILE__</span>, <span class="string"><span class="delimiter">"</span><span class="content">r:UTF-8</span><span class="delimiter">"</span></span>) <span class="keyword">do</span> |file|
puts file.external_encoding.name
p file.internal_encoding
file.each <span class="keyword">do</span> |line|
p [line.encoding.name, line]
<span class="keyword">end</span>
<span class="keyword">end</span>
hooopo<span class="instance-variable">hooopo:~/rubyist$ ruby show_external_encoding.rb
UTF-8
nil
["UTF-8", "open(FILE, \"r:UTF-8\") do |file|\n"]
["UTF-8", " puts file.external_encoding.name\n"]
["UTF-8", " p file.internal_encoding\n"]
["UTF-8", " file.each do |line|\n"]
["UTF-8", " p [line.encoding.name, line]\n"]
["UTF-8", " end\n"]
["UTF-8", "end\n"]
上面的例子展示了,通过设置IO对象的外部编码,使读取过来的字符串有了默认的编码标识。
加上内编码的情况就更绕了:
cat show_internal_encoding.rb
open("baidu.html", "r:GBK:UTF-8") do |file|
puts file.external_encoding.name
p file.internal_encoding
file.each do |line|
p [line.encoding.name, line[100..200]]
end
end
ruby show_internal_encoding.rb
GBK
#<Encoding:UTF-8>
["UTF-8", ">百度一下,你就知道
IO对象设置了内编码以后,会自动帮你把读来的字符串从外编码转换成内编码。即:
Iconv.iconv(internal_encoding, external_encoding, str)
如果IO对象的internal encoding和external encoding没有设置,他们会继承自Encoding.default_external 和 Encoding.default_internal
参考资源:
http://blog.grayproductions.net/articles/ruby_19s_three_default_encodings
http://www.ruby-forum.com/topic/178589
Ruby1.9的字符串编码改动非常大。在Ruby1.8,每个字符串都是字节序列,没有字符的概念。唯一一个和字符编码有关的$KCODE可以指定全局的编码。 但是$KCODE对字符串编码的改变很小,因为$KCODE只做了这样几件事:
让ruby解析器按照$KCODE的编码方式解析源代码
让inspect方法按$KCODE的编码方式显示字符
让正则按照$KCODE的编码方式匹配
影响inspect
ree-1.8.7-2011.03 :016 > $KCODE = "a"
=> "a"
ree-1.8.7-2011.03 :017 > p "Résumé"
"R\303\251sum\303\251"
=> nil
ree-1.8.7-2011.03 :018 > p "你好"
"\344\275\240\345\245\275"
=> nil
ree-1.8.7-2011.03 :019 > $KCODE = "U"
=> "U"
ree-1.8.7-2011.03 :020 > p "你好"
"你好"
=> nil
ree-1.8.7-2011.03 :021 > p "Résumé"
"Résumé"
=> nil
影响正则:
ree-1.8.7-2011.03 :027 > $KCODE = "a"
=> "a"
ree-1.8.7-2011.03 :028 > "你好".scan(/./)
=> ["\344", "\275", "\240", "\345", "\245", "\275"]
ree-1.8.7-2011.03 :030 > $KCODE = "U"
=> "U"
ree-1.8.7-2011.03 :031 > "你好".scan(/./)
=> ["你", "好"]
并且,$KCODE是一个全局的变量,它对所有文件产生作用,这在你的程序里引入了第三方库,时候会遇到麻烦。
Ruby1.9对字符编码的控制分的很细:
源文件编码
外编码
内编码
[h1]源文件编码[/h1]
Ruby1.9里,所有的字符串字面量都由字符序列+编码标识组成。 可以通过一个magick comment(# encoding: utf-8)来声明源代码里的字符串字面量的编码标识。这个comment针对每个文件起作用,不像1.8的$KCODE是在全局起作用。可以通过force_encoding方法来改变字符的编码标识(force_encoding并未转换编码,只改变标识)
# encoding: GBK
puts ENCODING #=> GBK
puts "".encoding #=> GBK
str = "你好".force_encoding "UTF-8"
puts str.encoding # => UTF-8
虽然force_encoding只改变了字符的编码标识,没有改变字节序列,但是,随着字符串的编码标识的改变,字符串的一些行为也跟着改变,比如inspect和each_char:
ruby-1.9.3-rc1 :017 > str = "你好"
=> "你好"
ruby-1.9.3-rc1 :018 > p str.encoding
#<Encoding:UTF-8>
=> #<Encoding:UTF-8>
ruby-1.9.3-rc1 :019 > str.each_char{|x| p "#{x}—> #{x.bytesize}"}
"你—> 3"
"好—> 3"
=> "你好"
ruby-1.9.3-rc1 :020 > str.force_encoding "GBK"
=> "\x{E4BD}\x{A0E5}\x{A5BD}"
ruby-1.9.3-rc1 :021 > str.each_char{|x| p "#{x}—> #{x.bytesize}"}
"\x{E4BD}—> 2"
"\x{A0E5}—> 2"
"\x{A5BD}—> 2"
=> "\x{E4BD}\x{A0E5}\x{A5BD}"
ruby-1.9.3-rc1 :022 >
[h1]外部编码[/h1] 字符串的来源可能有两种,一种是前面提到的源文件,另外一种是从外部IO读取到的。 对于第一种我们可以直接通过magick comment来设置字符串的默认编码标识。而从外部IO读取到的字符编码标识是通过IO对象的external_encoding和internal_encoding来设置的。
hooopohooopo</span><span class="symbol">:~</span>/rubyist<span class="error">$</span> cat show_external_encoding.rb
open(<span class="predefined-constant">__FILE__</span>, <span class="string"><span class="delimiter">"</span><span class="content">r:UTF-8</span><span class="delimiter">"</span></span>) <span class="keyword">do</span> |file|
puts file.external_encoding.name
p file.internal_encoding
file.each <span class="keyword">do</span> |line|
p [line.encoding.name, line]
<span class="keyword">end</span>
<span class="keyword">end</span>
hooopo<span class="instance-variable">hooopo:~/rubyist$ ruby show_external_encoding.rb
UTF-8
nil
["UTF-8", "open(FILE, \"r:UTF-8\") do |file|\n"]
["UTF-8", " puts file.external_encoding.name\n"]
["UTF-8", " p file.internal_encoding\n"]
["UTF-8", " file.each do |line|\n"]
["UTF-8", " p [line.encoding.name, line]\n"]
["UTF-8", " end\n"]
["UTF-8", "end\n"]
上面的例子展示了,通过设置IO对象的外部编码,使读取过来的字符串有了默认的编码标识。
加上内编码的情况就更绕了:
cat show_internal_encoding.rb
open("baidu.html", "r:GBK:UTF-8") do |file|
puts file.external_encoding.name
p file.internal_encoding
file.each do |line|
p [line.encoding.name, line[100..200]]
end
end
ruby show_internal_encoding.rb
GBK
#<Encoding:UTF-8>
["UTF-8", ">百度一下,你就知道
IO对象设置了内编码以后,会自动帮你把读来的字符串从外编码转换成内编码。即:
Iconv.iconv(internal_encoding, external_encoding, str)
如果IO对象的internal encoding和external encoding没有设置,他们会继承自Encoding.default_external 和 Encoding.default_internal
参考资源:
http://blog.grayproductions.net/articles/ruby_19s_three_default_encodings
http://www.ruby-forum.com/topic/178589