在ruby 1.6以后的版本中,默认情况下不会对汉字代码进行特殊的解释。若想处理汉字时,必须使用ruby -Ke等来设置$KCODE。
若想在Windows上使用SJIS时,应该设为ruby -Ks;若想在UNIX系列OS上使用EUC时,应该设为ruby -Ke。
另外,若在脚本首行中添加如下代码时
#! ruby -Ks
就可以将设定的选项置入脚本之中。恐怕这就是最常用的解决方法。
产生效果的时机不同。
例如,在SJIS编码文件中出现下列代码的话
$KCODE = 'SJIS' s = "表"
在设定$KCODE的值时,脚本的解析过程已经结束。(因为$KCODE的默认值是"NONE")所以字符串没有被看作是多字节内容。
如果使用选项-K来指定汉字编码的话,则在读入脚本之前已经生效,所以解析脚本时汉字代码会被正确识别。
另外,若包含汉字代码的脚本出现问题时,多半是因为JIS编码的汉字代码中包含与反斜杠("\")相同的代码所致。
只要正确设置了-K选项,就可以使用日语标识符。以日语汉字开头的变量名相当于以小写字母开头的变量名。但它的可移植性较低,我们不推荐您这样做。
在Hash中,也可以使用日语标识符,而且比较安全。
var = {'变量' => '值'}
var['变量'] = 1
设定$KCODE之后,使用split(//)或scan(/./)即可。
内部的String#tr在进行变换时,是以字节为单位的。在添加了require "jcode"之后,将以日语字符为单位进行处理。 (请参考jcode.rb)
下例是对平假名进行排序的例子(忽略了浊音、半浊音、拗音和拨音)。
require "jcode"
a = "ぁぃぅぇぉがぎぐげござじずぜぞだぢづでど" \
"ばびぶべぼぱぴぷぺぽゃゅょっゎ"
b = "あいうえおかきくけこさしすせそたちつてと" \
"はひふへほはひふへほやゆよつわ"
ary = %w(ふー ばー ばず)
p ary.sort
p ary.collect{|l| [l.tr(a,b), l]}.sort.collect!{|e| e[1]}
# => ["ばー", "ばず", "ふー"]
# ["ばー", "ばず", "ふー"]
另外,在1.7以后的版本中可以使用Enumerable#sort_by来这样改写最后一行
p ary.sort_by {|l| l.tr(a,b)}
即可。
尽管您可以使用正则表达式中表示范围的[あ-ん],但直接写出系统相关字符会影响程序的可读性。但也不能写成
gsub(/[\x84\xbf-\x88\x9f]/s, ' ')
这样。此时应该使用如下的小技巧
gsub(Regexp.compile("[\x84\xbf-\x88\x9f]", nil, 's'), ' ')
或
gsub(/#{"[\x84\xbf-\x88\x9f]"}/s, ' ')
用数值来表示2字节的代码,并将其替换为空白字符。(其实并非替换成空白字符,而是("〓"))
标准方法是使用nkf.so库或jcode.rb库进行变换。另外,还可以使用[RAA:Kakasi]库进行变换。
请参考[ruby-list:10505], [ruby-list:25839], [ruby-list:31238], [ruby-list:31240], [ruby-list:31508]等等
Ruby不支持半角假名。
# 在下例中,请将"ア"看作半角假名 ruby -Ks -e 'p "あア"' => "あ\261"
据说现在开发中的M17N版ruby就不会出现这种问题。
抽出多字节字符时,可能会将字符一分为二。此时,若正确设定了$KCODE的话,/./就不会匹配拆散的字符了。应对其加以充分利用
$KCODE = "e" p /./ =~ "あ"[0,1] # => nil # 注: 如果它并不是汉字的构成要素的话,就会进行匹配。 p /./ =~ "\xff" # => 0
下例中定义了一个jleft方法,它会从字符串左侧起抽出至多len字节的内容。
class String
def jleft(len)
return "" if len <= 0
str = self[0,len]
if /.\z/ !~ str
str[-1,1] = ''
end
str
end
end
$KCODE = 'e'
s = "あいうえお"
for i in -2 .. s.size+2
p [i, s.jleft(i)]
end
=> [-2, ""]
[-1, ""]
[0, ""]
[1, ""]
[2, "あ"]
[3, "あ"]
[4, "あい"]
[5, "あい"]
[6, "あいう"]
[7, "あいう"]
[8, "あいうえ"]
[9, "あいうえ"]
[10, "あいうえお"]
[11, "あいうえお"]
[12, "あいうえお"]
若限定使用EUC编码时,可以使用下面的方法。
class String
def jleft(len)
return "" if len <= 0
str = self[0, len]
if str.count("\xa1-\xfe") % 2 == 1
str[-1, 1] = ''
end
str
end
end
注:上述方法都不支持3字节字符。
可以使用NKF的-f选项。
require 'nkf'
p NKF.nkf("-ef11", "あいうえお、かきくけこ")
但是NKF会自动进行断字处理和空格调整,使我们无法进行精确控制。
若想自己来实现的话,可以使用10.10的方法。
class String
def jfold(len)
return "" if len <= 0
right = self.delete("\r\n")
while right and not right.empty?
left, right = right.unpack("a#{len} a*")
if /.\z/ !~ left
right[0,0] = left[-1,1]
left[-1,1] = ''
end
yield left
end
end
end
"あいうえお、かきくけこ".jfold(11) {|s|
puts s
}
# => あいうえお
、かきくけ
こ
实际上,它是每过n字节就进行一次folding,但并未考虑到TAB的位置问题。与nkf比较起来,它的速度非常慢。