`
Hooopo
  • 浏览: 336660 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

UTF8编码和正则表达式

    博客分类:
  • Ruby
阅读更多
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

分享到:
评论
29 楼 gokure 2009-12-02  
很好,学习了
28 楼 coolspeed 2009-11-23  
Edit....

(没弄清chcp)
27 楼 ray_linn 2009-11-23  
Hooopo 写道
你的是什么系统啊?很漂亮。。我的是xp..


Win 7呀,XP也是一样的。只是win 7的截图工具特别好用。


我用ironruby打印同样的,输出似乎更干净,没有“们”后面的小方框。。


理论上用ruby这样的ansi string,应该效率更低,每次调用windows系统的api就必须转码2次。。


26 楼 Hooopo 2009-11-23  
你的是什么系统啊?很漂亮。。我的是xp..
25 楼 ray_linn 2009-11-23  
在我这里无法再现:





PS: Windows下的utf-8编辑器多了去,最常见的就是notepad,选择另“存外为”可以存为utf-8,unicode,uncode-le,ansi不同编码。


Windows的所有API都是以unicode为编码的,这在当时算是十分先进的,为了兼容ansi,Windows还是提供了ansi的API,但是这些API本身并没有实质内容,唯一做的是转码,调用unicode api,再转码。
24 楼 Hooopo 2009-11-23  
ray_linn 写道
Hooopo 写道
windows下大多数编辑器(比如irb,ruby自带的SciTE)不支持UTF-8编码,所以解决编码问题最先是换个支持UTF-8编码的编辑器,比如Netbeans,这样才能保证你的输入字符编码是UTF-8.


两步:

1. chcp 65001
2. 在命令行标题栏上点击右键,选择"属性"->"字体",将字体修改为True Type字体"Lucida Console",然后点击确定将属性应用到当前窗口。

如图:



原因:dos 窗口时兼容以前的ansi的,windows大部分api是unicode.

上面两步执行完连irb也不能运行了。为什么?
引用
Active code page: 65001

C:\Documents and Settings\hoopo>irb

C:\Documents and Settings\hoopo>irb

C:\Documents and Settings\hoopo>irb

C:\Documents and Settings\hoopo>
23 楼 ray_linn 2009-11-22  
Hooopo 写道
windows下大多数编辑器(比如irb,ruby自带的SciTE)不支持UTF-8编码,所以解决编码问题最先是换个支持UTF-8编码的编辑器,比如Netbeans,这样才能保证你的输入字符编码是UTF-8.


两步:

1. chcp 65001
2. 在命令行标题栏上点击右键,选择"属性"->"字体",将字体修改为True Type字体"Lucida Console",然后点击确定将属性应用到当前窗口。

如图:



原因:dos 窗口时兼容以前的ansi的,windows大部分api是unicode.
22 楼 sevk 2009-07-03  
ruby1.9 果然方便, 连 iconv 库都集成进去了.
直接 str.encoding
str.force_encoding("utf-8")
21 楼 wolfplanet 2009-05-06  
我用Linux。。。。
20 楼 oCameLo 2009-04-22  
坦白说,慢一点我是不在乎的,何况VB6和Python3也未必慢到哪里去。西方人不爽是个大问题,那也可以用locale,总比现在乱糟糟的要好些。

写一个ruby出来我肯定是没那个本事滴,不过那个GC大补丁也不是松本桑写的吧?对其人的敬意当然是有的,大着胆子说的那一句,其实也就是有点嫉妒,嫉妒Perl有CPAN,嫉妒Python抱上了Google的粗大腿。嗯,意思跟你说ruby社区歧视windows用户其实差不多。
19 楼 whaosoft 2009-04-22  
只要一沾带中文的 都那么麻烦
18 楼 night_stalker 2009-04-22  
oCameLo 写道

这些问题的确只要小心一点都可以避免,但一直都要很小心不也挺麻烦的。比如说检查字符串,难道都得写m == n and m.encoding == n.encoding?

不用比较 encoding 的。

oCameLo 写道

预先检查并统一字符串编码可能可以解决一部分问题,但这样的话在每一个类每一个模块里都要干同样的事,还是又啰嗦又容易出错。

magic column 可以解决一部分啰嗦的问题。
不满意的地方就自己打开 String 修改,基本不会啰嗦。

oCameLo 写道

插个花,按说ruby帮老大是日本人,不应该会有这种问题才对。可是ruby一开始就没有支持Unicode的打算,现在又整这么一出,再加上性能问题GC问题,大着胆子说一句,有时候还真有些怀疑那谁的眼光和能力。

普遍性能是变好了,西方人可能不爽:string 更适合处理多字节字符了,但处理纯 ascii 会慢很多。
特定场景会差一些,而性能…… 等你的算法优化到极限了再来谈性能吧……
闹得沸沸扬扬的 GC 问题不是补丁上了么? 虽然落后、破烂,但是它能工作,很了不起了。
不信可以自己实现个 ruby,感受一下……
17 楼 oCameLo 2009-04-22  
#encoding只对当前文件有效。

按理说跟所有外部模块和类传递的字符串在使用前都需要检查编码,而你可以这样做,写模块和类的人未必会这样做,所以我才说又麻烦又容易出错。

当然了,问题是可以解决的。首先自己小心一点,如果别人不小心,代码拿来改就是了。不当他是问题,当然就不是问题,1.8这么些年还不是照样用得好好的。
16 楼 Hooopo 2009-04-22  
呃,我拿ruby来干杂事。。

引用
你转的这篇东西里还有几个问题没提到,Net::HTTP抓回来的东西默认编码是ASCII-8BIT,File.open('test.txt').read.encoding在Windows里又是GBK。

这个我还真没注意,因为在1.86中没有检查字符编码的方法,不像1.9,str.encoding=>ascii8bit
刚才试了一下确实Het::HTTP返回的string的encoding是ASCII-8BIT,而且open-uri也一样。
但是我已经说了,在1.86中字符串的默认处理方式(不设置$KCODE的情况下)就是ASCII-8BIT,即便用iconv转换成utf-8,ruby在内存中也是按照字节方式去解析的。比如:
irb(main):046:0> h.size
=> 35113
irb(main):047:0> h.scan(/./).size
=> 34728
irb(main):048:0> h.scan(/./u).size
=> 29228


引用
这些问题的确只要小心一点都可以避免,但一直都要很小心不也挺麻烦的。比如说检查字符串,难道都得写m == n and m.encoding == n.encoding?


预先检查并统一字符串编码可能可以解决一部分问题,但这样的话在每一个类每一个模块里都要干同样的事,还是又啰嗦又容易出错。

这个当然不必要这样做。不是可以这样嘛:#encoding :utf-8
当然如果是网络或从其他文件读取的内容可以强制转换一下s.force_encoding("utf-8")
这样不就都统一了嘛,比1.8.6要舒服不知道多少倍。

引用
更何况别忘了,咱们中国人被编码问题蹂躏得够久,可西方人向来是不在乎这些的。在他们写的库里会遇到编码问题,几乎肯定是会发生的事。

我对1.9的了解其实不多,不知道ruby对这些问题有没有预防性的措施。不过就我看到的用到的东西来说,总觉得日后会麻烦一堆。

插个花,按说ruby帮老大是日本人,不应该会有这种问题才对。可是ruby一开始就没有支持Unicode的打算,现在又整这么一出,再加上性能问题GC问题,大着胆子说一句,有时候还真有些怀疑那谁的眼光和能力。

现在编码不是问题了,gc不太清楚。。其实1.9最大的问题是很多库都没跟上来。
15 楼 oCameLo 2009-04-22  
呃,我拿ruby来干杂事。。

你转的这篇东西里还有几个问题没提到,Net::HTTP抓回来的东西默认编码是ASCII-8BIT,File.open('test.txt').read.encoding在Windows里又是GBK。

这些问题的确只要小心一点都可以避免,但一直都要很小心不也挺麻烦的。比如说检查字符串,难道都得写m == n and m.encoding == n.encoding?

预先检查并统一字符串编码可能可以解决一部分问题,但这样的话在每一个类每一个模块里都要干同样的事,还是又啰嗦又容易出错。

更何况别忘了,咱们中国人被编码问题蹂躏得够久,可西方人向来是不在乎这些的。在他们写的库里会遇到编码问题,几乎肯定是会发生的事。

我对1.9的了解其实不多,不知道ruby对这些问题有没有预防性的措施。不过就我看到的用到的东西来说,总觉得日后会麻烦一堆。

插个花,按说ruby帮老大是日本人,不应该会有这种问题才对。可是ruby一开始就没有支持Unicode的打算,现在又整这么一出,再加上性能问题GC问题,大着胆子说一句,有时候还真有些怀疑那谁的眼光和能力。
14 楼 Hooopo 2009-04-21  
oCameLo 写道
所谓不成熟,看你用不用得到了,我平常会用到的好像就只有sqlite3还有问题。

1.9加了些很不错的东西,string方面虽然还不能让人满意,但也总是有改进,看看这个:http://otnth.blogspot.com/2009/04/unicode-in-ruby-19.html

1.9我以前用过,感觉在处理字符方面真的比1.86要舒服很多。
您是用ruby来做什么的?
13 楼 Hooopo 2009-04-21  
oCameLo 写道
所谓不成熟,看你用不用得到了,我平常会用到的好像就只有sqlite3还有问题。

1.9加了些很不错的东西,string方面虽然还不能让人满意,但也总是有改进,看看这个:http://otnth.blogspot.com/2009/04/unicode-in-ruby-19.html

Ruby 1.9终于抛弃了丑陋的jcode,提供一定程度上的Unicode支持。只不过我总觉得有点儿不对劲,Ruby当前采用的处理方式,很可能会带来一些新的问题。

String有了encoding属性,部分方法的处理单位也由字节改为字符。源码文件的默认编码为US-ASCII,如果在代码中写了中文,就必须指定encoding。如果不想写,也可以用BOM。

# encoding: utf-8

s = '幺贰和叁'
puts s.encoding     # => UTF-8
puts s.length     # => 4
puts s.bytesize     # => 12

不同encoding字符串之间可以直接比较,也就是说从今以后比较字符串都要考虑编码问题,搞不好会有很多Bug因此而产生。

# encoding: utf-8
s = '位'.encode('gbk')
t = 'λ'
puts s.bytes.to_a == t.bytes.to_a # => true
puts s == t # => false
puts s == t.force_encoding('gbk') # => true

正则表达式方面更乱,encoding不同“=~”一定会报错,但match方法却不一定。

# encoding: utf-8

s = 'abc'.encode('gbk')
p s.match(/b/) # => #<MatchData "b">

s =~ /b/ # => incompatible encoding regexp match (UTF-8 regexp with GBK string) (Encoding::CompatibilityError)

s = '位'.encode('gbk')
p s.match('λ') # => incompatible encoding regexp match (UTF-8 regexp with GBK string) 
(Encoding::CompatibilityError)
IO方面也添加了encoding支持,不过还不支持BOM,所以读取带BOM的文件得多一个步骤。

File.open('utf8_with_bom.txt', 'r:utf-8') do |f|
  f.ungetc c unless (c = f.getc)=="\uFEFF"
  # ...
end

Python 3.0中一个很大的变化就是区分了String和Byte,所有String都是Unicode,说不定有一天Ruby也会走Python的老路,希望这只是我乌鸦嘴吧。


我觉得上面说的1.9的问题没什么的,既然可以判断编码方式了,不同编码方式的比较前只要判断一下就可以的,是可以控制的。而正则表达式也是一样,既然能判断编码方式,也能转换,这有什么问题呢?

12 楼 oCameLo 2009-04-21  
所谓不成熟,看你用不用得到了,我平常会用到的好像就只有sqlite3还有问题。

1.9加了些很不错的东西,string方面虽然还不能让人满意,但也总是有改进,看看这个:http://otnth.blogspot.com/2009/04/unicode-in-ruby-19.html
11 楼 Hooopo 2009-04-21  
oCameLo 写道
呃,楼上的童鞋,你应该去看看1.9了。

为什么呢?现在1.9的库还不是很成熟呀。。
10 楼 oCameLo 2009-04-21  
呃,楼上的童鞋,你应该去看看1.9了。

相关推荐

    C语言正则表达式库

    它包含了对UTF-8编码的内置支持,并可以通过配置支持其他Unicode编码格式。 3. **回溯算法**:PCRE库使用了高效的回溯算法来执行正则表达式匹配。虽然这可能会导致性能问题,但通过优化的匹配引擎和使用预编译模式...

    易语言正则表达式匹配中文

    例如,可以使用两个字节的UTF-8编码来表示中文字符,其对应的正则表达式可能是`\xd0[\x80-\xff]|\xe0[\xa0-\xbf][\x80-\xbf]|\xed[\xa0-\xed][\x80-\xbf]`。这个表达式涵盖了大部分常用中文字符的UTF-8编码。 在...

    判断不同编码的正则表达式

    对于不同的字符编码(如GB2312、UTF-8等),其对应的正则表达式也会有所不同。本文将探讨如何通过PHP语言中的正则表达式来判断字符串是否为GB2312或UTF-8编码。 #### GB2312编码判断 GB2312是中国大陆使用的一种...

    VC++支持中文的正则表达式函数库

    - **编码支持**:由于库专门优化了对中文的支持,因此可能使用了宽字符或者UTF-8编码,确保你的项目设置与之兼容。 - **性能**:尽管库是为VC++定制的,但其性能可能与原生的正则表达式库(如Boost.Regex或std::...

    正则表达式提取网页编码

    本文将深入探讨如何利用正则表达式来提取网页中的编码信息。 ### 正则表达式提取网页编码 在网页中,编码信息通常位于`&lt;meta&gt;`标签内,通过`charset`属性指定。例如,在以下HTML代码片段中: ```html ;charset=...

    《正则表达式大全(上)》(高清晰)pdf版

    《正则表达式大全(上)》是一本深入讲解正则表达式的电子书籍,主要针对计算机领域的专业人士和学习者,提供了丰富的正则表达式实例及其应用场景。正则表达式是一种强大的文本处理工具,用于模式匹配、查找、替换等...

    正则表达式测试工具

    5. **编码支持**:处理不同编码的文本,如ASCII、UTF-8等。 6. **模式调试**:提供调试模式,查看匹配的每一个细节,如匹配的子串、捕获组等。 7. **学习资源**:部分工具内嵌正则表达式教程,方便初学者学习。 在...

    正则表达式乱码查看器

    "正则表达式乱码查看器"通过其内置的解码功能,可以有效地识别和显示这些乱码,帮助用户准确地查看原本被编码问题掩盖的信息。 "乱码查看器.exe"是程序的主执行文件,用户可以通过运行这个文件启动软件。它可能包含...

    mingw pcre8.12正则表达式库

    此外,PCRE还支持UTF-8编码,可以处理多语言字符,以及Unicode属性支持,这对于处理全球化应用中的文本非常有用。 在实际编程中,你可能需要了解PCRE的一些特殊标志和选项,如`PCRE_CASELESS`(不区分大小写)、`...

    正则表达式统计汉字

    这里的 `"utf-8"` 参数指定了字符串的编码方式,确保函数能够正确识别和计数。 ##### 5. 统计特定字符出现次数的方法 本例中,我们通过先用正则表达式移除所有非汉字字符,然后再统计剩余字符串的长度,以此来得到...

    正则表达式计数代码行数

    为了提高效率和准确性,还可以考虑使用预编译的正则表达式对象,并使用适当的方法处理编码问题。 在进行代码分析时,正则表达式的灵活性和强大功能使得它成为不可或缺的工具。通过熟练掌握正则表达式,开发者能够...

    易语言源码正则表达式匹配中文.7z

    在中文字符匹配方面,由于中文字符通常由多个字节组成,如UTF-8编码下每个汉字占用3个或4个字节,因此在编写正则表达式时需要特别考虑编码方式。在易语言中,我们可能需要使用支持多字节编码的正则库,如PCRE(Perl ...

    非常好用的正则表达式调试工具

    8. **编码支持**:处理不同编码格式的文本,如UTF-8、GBK等。 9. **自定义设置**:允许用户自定义匹配选项,例如是否区分大小写、是否全局匹配等。 10. **导出与分享**:能够导出测试用例或正则表达式,方便团队...

    C#字符串和正则表达式参考手册

    在第一章“系统处理文本的方式”中,作者介绍了计算机对文本的存储、编码方式,如ASCII、Unicode和UTF-8等,以及C#中的字符和字符串类型。这部分内容有助于理解不同编码格式间的转换和文本处理的基本原理。 第二章...

    C#正则提取中文

    然而,需要注意的是,正则表达式的编写需要对字符编码有深入的理解,尤其是当涉及到多字节字符集,如UTF-8、UTF-16等,因为不同的编码方式会影响正则表达式的匹配行为。此外,对于复杂的数据结构和模式,正则表达式...

    小巧强悍的工具Convert:正则表达式测试/代码转换/翻译/编解码/加解密

    4、Encoding&lt;-&gt;Decoding:编码和解码,包括Base64、UTF-8、Unicode、HTML(&)、URL(%)…… 5、Encryption&lt;-&gt;Decryption:加密和解密,包括高级标准算法(AES)、数据标准算法(DES)、三重数据标准算法(TripleDES)、...

    Python实现正则表达式匹配任意的邮箱方法

    同时,我们使用了coding声明来确保Python文件的编码为UTF-8,这对于处理包含中文字符的输入输出是很有必要的。 最后,通过对正则表达式的学习和实践,可以大幅度提高处理文本数据的能力,尤其在进行文本验证、数据...

    正则表达式测试软件_RegexBuddy

    5. **编码支持**:RegexBuddy支持多种字符编码,如ASCII、UTF-8等,这使得处理包含不同语言和特殊字符的文本变得轻松。 6. **跨平台兼容性**:虽然我们只提到RegexBuddy.exe,这通常意味着Windows版本,但该软件也...

    易语言正则表达式类匹配中文源码

    这通常涉及到对UTF-8编码的支持,因为中文字符在计算机中是以多字节的形式存储的,与英文字符的单字节编码有所不同。开发者可能需要编写或利用现有的易语言类来处理中文正则表达式,包括编译正则模式、执行匹配、...

    正则表达式 调试工具

    5. **编码支持**:支持多种字符编码,如ASCII、UTF-8等。 6. **错误提示**:当正则表达式有误时,提供清晰的错误信息,便于修正。 7. **学习资源**:一些工具还提供了正则表达式语法的学习资料,方便用户提升技能...

Global site tag (gtag.js) - Google Analytics