ruby 程序中的文字编码

1,问题

在写一个统计代码行数的脚本时遇到一个问题:

代码:

file_name = "code.rb"
c = 0
File.foreach(file_name) do |x| next unless x !~ /^\s*(#|\s*$)/ c = c + 1 end

运行的时候报错

ArgumentError: invalid byte sequence in GBK
        =~ at org/jruby/RubyRegexp.java:1486
        =~ at org/jruby/RubyString.java:1652
        !~ at org/jruby/RubyKernel.java:2158
  __file__ at ddd.rb:20
   foreach at org/jruby/RubyIO.java:3352
    (root) at ddd.rb:17

提示说GBK编码中有不识别的内容。大概情况是这样(有待考证),由于使用的是中文的操作系统(win7),ruby根据系统的语言,采用对应编码方式(GBK),从文件中取得的字符串默认为GBK的格式。

file_name = "code.rb"
c = 0
)  do
    |x|
    p x.encoding
    next unless x !~ /^\s*(#|\s*$)/u
    c = c + 1
end


p "1234567890".encoding

得到的结果是:

#<Encoding:GBK>

#<Encoding:GBK>

#<Encoding:GBK>

#<Encoding:US-ASCII>

从文件中取得内容是GBK的,一个普通的字符串是ASCII。

如果给rb脚本加上# -*- coding:utf-8 -*-,即:

# -*- coding:utf-8 -*-
file_name = "code.rb"
c = 0
file_name)  do
    |x| 
p x.encoding
next unless x !~ /^\s*(#|\s*$)/u
c = c + 1
end
p "1234567890".encoding

这时会将普通字符串的格式都默认为UTF-8,而从文件中读取的内容呢?请看结果:

#<Encoding:GBK>
#<Encoding:GBK>
#<Encoding:GBK>
#<Encoding:UTF-8>

结果显示,从文件中读取的内容和设置的rb程序编码方式是无关的。

对于要读取的文件是UTF-8格式,而取得的字符串却是GBK,做正则表达式判断的时候就会报错了。对于这种情况,可以设置取文件时采用UTF-8,好像只有open方法有此选项:

# -*- coding:utf-8 -*-
file_name = "code.rb"
c= 0
open(file_name, "r:utf-8") do |f|
    f.each do |line|
        next unless line !~ /^\s*(#|\s*$)/
        c = c + 1
        p line.encoding
    end
end

p "1234567890".encoding

结果是:

#<Encoding:UTF-8>
#<Encoding:UTF-8>
#<Encoding:UTF-8>
#<Encoding:UTF-8>

2,结论:

# -*- coding:utf-8 -*-   
影响的是rb代码中普通字符串的编码方式。
open(file_name, "r:utf-8")可以控制读取文件中编码方式。
查阅资料的过程中涉及到了
$KCODE = 'u'   # 或者为$KCODE = 'utf-8' 

《ruby程序设计268技》中说,默认的文字编码可以通过$KCODE环境变量设置,可实际操作过程中,并没有效果。

《松本行弘的程序世界》中说,给全局变量$KCODE设置适当的值,可以给不带选项的正则表达式制定编码方式。

$KCODE = 'e'
#全部的文本按照EUC-JP为基础
$KCODE = 'u'
#全部的文本按照UTF-8为基础
re = /foo 認証情報の入力/u
#UTF-8对应的正则表达式(u选项制定)
chars = 'abc 認証情報の入力'.split(//u)
#以问子伟单位分割string

附字符串的UTF-8 和GBK的转换方法:

require 'iconv'
def utf82gb(str)
  Iconv.iconv("GBK",'UTF-8',str.to_s)
end

-----------------以下更新于2014年3月8日-----------

根据双飞燕《Ruby编程语言》,2.4.2源编码和默认外部编码

源编码:Ruby解释器解读脚本中的字符,通常采用编码注释来设定一个文件的源编码,例如:# coding: utf-8

默认外部编码:Ruby从文件或者流中读取内容时采用的默认编码,对于ruby来说是全局性的,基于电脑的区域设置来进行设置的,和电脑的操作系统语言相关。

脚本中打印 Encoding.default_external,输出结果是#<Encoding:GBK>,因为返回的是Encoding对象。

可以通过如下四种方式设置默认外部编码:

ruby -E utf-8

ruby -Eutf-8

ruby --encoding utf-8

ruby --encoding=utf-8