转自:http://www.iteye.com/topic/369753
ruby的编码问题是每一个ruby初学者的最大困扰。下面把我的总结和大家分享一下,希望对大家有帮助。
注:系统windows xp 平台:ruby 1.8.6 (without rails)1。编辑器
windows下大多数编辑器(比如irb,ruby自带的SciTE)不支持UTF-8编码,所以解决编码问题最先是换个支持UTF-8编码的编辑器,比如Netbeans,这样才能保证你的输入字符编码是UTF-8.
有了UTF-8编码的编辑器还不够,还要保证输出端不出现乱码,那就一定要用iconv这个库转换。因为ruby程序输出都是在windows 的cmd控制台的,而控制台的编码是GBK。
- require'iconv'
- class String
- def to_gbk
- Iconv.iconv("GBK//IGNORE","UTF-8//IGNORE",self).to_s
- end
- def to_utf8
- Iconv.iconv("UTF-8//IGNORE","GBK//IGNORE",self).to_s
- end
- end
- utf8_string="\344\273\254"
- puts utf8_string #在irb中输出“浠”=>乱码
- puts utf8_string.to_gbk #在irb中输出“们”=>正确输出
- #在irb输入一汉字
- gbk_string="\303\307"
- puts gbk_string #输出"们"
- p gbk_string.to_utf8 #输出"\344\273\254"
判断一个段文本是否是UTF-8编码:
- class String
- def utf8?
- unpack('U*') rescue return false
- true
- end
- end
- utf8_string.utf8? #true
- gbk_string.utf8? #false
上面介绍了如何输入,显示,判断和转换utf8字符。但是只有这些还不够,下面绍如何处理。
ruby默认处理字符是按照ascii编码方式(这个和你输入的编码方式无关)
比如:
- puts utf8_string.size #输出3
- puts gbk_string.size #输出2
从这个例子我们可以看到,size方法的返回值实际上是这个字符串在某个固定的字符集下被编码为几个字节,从而返回它
jcode库还提供了一些有用的方法,比如jlength和each_char.
用jcode之前必须设置$KCODE="UTF-8"
- $KCODE="u"
- require'jcode'
- puts utf8_string.size #还是3
- puts utf8_string.jsize #1,正是我们想要的结果
- puts gbk_string.jsize #也是1
这里还有一个方法,叫做mbchar?的,他检测一个字符串是否是多字节的.
- puts utf8_string.mbchar? #0
- puts gbk_string.mbchar? #nil 这个有点问题了.....
- puts "aaaaa".mbchar? #nil
jcode库还重新定义了chop, delete, squeeze, succ, tr, 和tr_s.这些方法.这些方法都是为多字节的字符串所定义的
我们还可以使用each_char来打印出所有的多字节字符:
- str=utf8_string << "hello"
- str.each_char.map {|e| e.to_gbk} #=> ["们", "h", "e", "l", "l", "o"]
- str.each_char.map {|e| [e.size,e.jsize]} #=> [[3, 1], [1, 1], [1, 1], [1, 1], [1, 1], [1, 1]]
unpack方法,有选项来帮助我们操作unicode字符串,如果他的参数为U*的话,则将会解码当前的字符串,使用utf-8编码。也就是说他会返回一个整数数组,而对应的还有一个pack方法,他则是编码的:
- string=(utf8_string << "hooopo")*10
- puts string.unpack("U*") #=> [20204, 104, 111, 111, 111, 112, 111, 20204, 104, 111, 111, 111, 112, 111, #20
- #204, 104, 111, 111, 111, 112, 111, 20204, 104, 111, 111, 111, 112, 111, 20204, 1
- #04, 111, 111, 111, 112, 111, 20204, 104, 111, 111, 111, 112, 111, 20204, 104, 11
- #1, 111, 111, 112, 111, 20204, 104, 111, 111, 111, 112, 111, 20204, 104, 111, 111
- #, 111, 112, 111, 20204, 104, 111, 111, 111, 112, 111]
用unpack做提取中文字符等操作是相当强大的:
- string.unpack("U*").select{|e| (0x4E00..0x9FA5).include?e}.pack("U*").to_gbk
- #=> "们们们们们们们们们们"
当然提取中文可以用scan
- string.scan(/./u).select{|e| e.size==3}.join.to_gbk
- #=> "们们们们们们们们们们"
有个bug就是size==3的不一定是中文,也有可能是日文。。。但是这个对处理中文网页是没什么问题的。
提取字符串最强大的还是正则表达式,不过对中文这个问题,貌似ruby1.8.6的正则表达式不是很好处理
- s=[0x4E00].pack("U")
- e=[0x9FA5].pack("U")
- reg=Regexp.new("[#{s}-#{e}]",false,"U")
- puts string.scan(reg).join.to_gbk
- #=> "们们们们们们们们们们"
这里说明一下,虽然ruby默认处理字符串的方式是按照ascii,但是如果设置$KCODE="u"会按照UTF-8方式处理,但是在正则表达式中只要设置正则字面量u(/reg/u)就会安装utf8方式处理,多以,如果知道要匹配字符范围的话,ruby 1.8.6的正则表达式也能很好的处理utf8
其他相关:
1.这里是pack和unpack的中文介绍http://www.souzz.net/html/345/23498.html
2.ruby每周一测-中英文混合字符串截取http://www.iteye.com/topic/201531
3. icu4r: IBM ICU库的Ruby扩展,添加了诸如UString, URegexp等类来处理Unicode。(文档链接)http://icu4r.rubyforge.org/
4.utf8proc: 一个很小型的库,便利字符串中的的字符然后一个个转过去,给String类和Interger类添加了了一些方法,比如String#utf8map和Integer#utf8 http://www.flexiguided.de/publications.utf8proc.en.html