在ruby 1.6以后的版本中,默认情况下不会对汉字代码进行特殊的解释。若想处理汉字时,必须使用ruby -Ke等来设置$KCODE。
若想在Windows上使用SJIS时,应该设为ruby -Ks;若想在UNIX系列OS上使用EUC时,应该设为ruby -Ke。
另外,若在脚本首行中添加如下代码时
#! ruby -Ks就可以将设定的选项置入脚本之中。恐怕这就是最常用的解决方法。
10.2 选项-K和$KCODE有什么不同?产生效果的时机不同。
例如,在SJIS编码文件中出现下列代码的话
$KCODE = 'SJIS' s = "表"在设定$KCODE的值时,脚本的解析过程已经结束。(因为$KCODE的默认值是"NONE")所以字符串没有被看作是多字节内容。
如果使用选项-K来指定汉字编码的话,则在读入脚本之前已经生效,所以解析脚本时汉字代码会被正确识别。
另外,若包含汉字代码的脚本出现问题时,多半是因为JIS编码的汉字代码中包含与反斜杠("\")相同的代码所致。
10.3 可以使用日语标识符吗?只要正确设置了-K选项,就可以使用日语标识符。以日语汉字开头的变量名相当于以小写字母开头的变量名。但它的可移植性较低,我们不推荐您这样做。
在Hash中,也可以使用日语标识符,而且比较安全。
var = {'变量' => '值'} var['变量'] = 1 10.4 如何从包含日语字符的字符串中依次抽出1个字符?设定$KCODE之后,使用split(//)或scan(/./)即可。
10.5 tr("あ","a")运作不正常,应如何处置?内部的String#tr在进行变换时,是以字节为单位的。在添加了require "jcode"之后,将以日语字符为单位进行处理。 (请参考jcode.rb)
10.6 如何对平假名进行排序?下例是对平假名进行排序的例子(忽略了浊音、半浊音、拗音和拨音)。
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)}即可。
10.7 如何用空白来替代SJIS中从84BF到889F之间的系统相关代码?尽管您可以使用正则表达式中表示范围的[あ-ん],但直接写出系统相关字符会影响程序的可读性。但也不能写成
gsub(/[\x84\xbf-\x88\x9f]/s, ' ')这样。此时应该使用如下的小技巧
gsub(Regexp.compile("[\x84\xbf-\x88\x9f]", nil, 's'), ' ') 或 gsub(/#{"[\x84\xbf-\x88\x9f]"}/s, ' ')用数值来表示2字节的代码,并将其替换为空白字符。(其实并非替换成空白字符,而是("〓"))
10.8 如何进行全角-半角字符的变换?标准方法是使用nkf.so库或jcode.rb库进行变换。另外,还可以使用[RAA:Kakasi]库进行变换。
请参考[ruby-list:10505], [ruby-list:25839], [ruby-list:31238], [ruby-list:31240], [ruby-list:31508]等等
10.9 关于半角假名的问题Ruby不支持半角假名。
# 在下例中,请将"ア"看作半角假名 ruby -Ks -e 'p "あア"' => "あ\261"据说现在开发中的M17N版ruby就不会出现这种问题。
10.10 怎样从包含日语字符的字符串中抽出n字节的内容?抽出多字节字符时,可能会将字符一分为二。此时,若正确设定了$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字节字符。
10.11 怎么让日语文本在第n个字处换行?可以使用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比较起来,它的速度非常慢。