分享 初学者连载系列之六:Ruby 编程之正则表达式详解

kevinhua · April 06, 2012 · Last by uestc_bird replied at April 18, 2016 · 25098 hits

系列文章原载于自己的博客,TOPI.CO (http://topi.co) ,某天不小心就 push 错啦,懒得从头再来,上传到 Ruby-China 来,一是方便自己回顾,另外也方便跟我一样的初学者

之前简单介绍过 Ruby 编程之正则表达式,过于简单,所以在网上查询了些资料,继续补充。

先推荐一个在线的 Ruby 正则表达式编辑器:Rubular,现在已经支持 Ruby 1.9 啦。

如前文所说,Ruby 的正则表达式以/pattern/为模式,表达式返回一个 RegExp 的对象。可以通过内省方法来查看:

puts /RoR|Rails/.class #-> RegExp


一般规则 (为正常显示,都放在代码块内)

/a/匹配字符a。    
/\?/匹配特殊字符?。特殊字符包括^, $, ? , ., /, \, [, ], {, }, (, ), +, *.    
.匹配任意字符,例如/a./匹配ab和ac。    
/[ab]c/匹配ac和bc,[]之间代表范围。例如:/[a-z]/ , /[a-zA-Z0-9]/。    
/[^a-zA-Z0-9]/匹配不在该范围内的字符串。    
/[\d]/代表任意数字
/[\w]/代表任意字母,数字或者_
/[\s]/代表空白字符,包括空格,TAB和换行。    
/[\D]/,/[\W]/,/[\S]/均为上述的否定情况。 


高级规则

?代表0或1个字符。/Mrs?\.?/匹配"Mr","Mrs","Mr.","Mrs."。 
*代表0或多个字符。/Hello*/匹配"Hello","HelloJack"。 
+代表1或多个字符。/a+c/匹配:"abc","abbdrec"等等。 
/d{3}/匹配3个数字。 
/d{1,10}/匹配1-10个数字。 
/d{3,}/匹配3个数字以上。 
/([A-Z]\d){5}/匹配首位是大写字母,后面4个是数字的字符串。


正则表达式操作

String 和 RegExp 均支持=~match两个查询匹配方法:

puts "I can say my name" =~ /name/ #-> 13

a = /name/.match("I can say my name, my name I can say") #-> a is MatchData
puts a[0] #-> name


可以看出,如果能够匹配,=~返回匹配的字符串位置,而 match 返回一个 MatchData 对象。如果不匹配,则返回 nil。MatchData 可以取出其中符合各个子匹配(或子模式)的内容,看下面的例子:

b1=/[A-Za-z]+,[A-Za-z]+,Mrs?\./.match("Jack,Wang,Mrs., nice person")
puts b1[0] #-> Jack,Wang,Mrs

b2=/(([A-Za-z]+),([A-Za-z]+)),Mrs?\./.match("Jack,Wang,Mrs., nice person:)
puts b2[0] #-> Jack,Wang,Mrs
puts b2[1] #-> Jack,Wang
puts b2[2] #-> Jack
puts b2[3] #-> Wang


m[0] 返回匹配匹配主表达式的字符串,下面的方法是等同的:m[n]==m.captures[n]

Ruby 也自动的为我们填写一些全局变量,它们以数字做名,$1, $2, 等等,$1包含的是正则表达式中从左侧开始的第一对小括号内的子模式所匹配的字符串,以此类推。我们看出匹配时,是从外到内,从左到右的顺序。

贪婪量词和不贪婪量词

量词*(表示零个或多个)+(表示一个或多个)贪婪的,它们会匹配尽可能多的字符,我们可以在*和+后面加一个?,使它成为非贪婪量词

下面代码是:1 个或多个字符后接一个感叹号。

teststr="abcd!efg!"
match=/.+!/.match(teststr)
puts match[0] #-> abcd!efg!

limitmatch=/.+?!/.match(teststr)
puts limitmatch[0] #-> abcd!


锚是指必须满座一定的条件,才能继续匹配:

^     行首
$     行尾
\A    字符串的开始
\z    字符串的结尾
\Z    字符串的结尾(不包括最后的换行符)
\b    单词边界


c=/\b\w+\b/.match("!!Stephen**")
puts c[0] #-> Stephen


前视断言

前视断言表示想要知道下一个指定的是什么,但并不匹配

  • 肯定的前视断言 (?=)

假设我们想要匹配一个数的序列,该序列以一个圆点结束,但并不想把圆点作为模式匹配的一部分

teststr="123 456 789. 012"
m=/\d+(?=\.)/.match(teststr)
puts m[0] #-> 789


  • 否定的前视断言 (?!)

上例,如果/\d+(?=\.)/改为/\d+(?!\.)/,则puts m[0]输出显示为 123。

修饰语

修饰语位于正则表达式最结束正则表达式的正斜杠的后面

  • i使正则表达式对大小写不敏感

例如,/abc/i可以匹配 Abc,abc,ABC 等。

  • m使得正则表达式可以和任何字符匹配,包括换行符,通常情况下圆点通配符不匹配换行符。

字符串与正则表达式的相互转换

  • 字符串内插进正则表达式
teststr="a.c"
re=/#{Regexp.escape(teststr)}/
puts re.match("a.c")[0] #-> a.c
test=re.match("abc")
puts test[0] #-> Nil


  • 正则表达式转换成字符串
puts /abc/.inspect #-> /abc/


使用正则表达式的常见方法

  • 用于 if 和 while 等

  • 用于 gsub、grep 等

  • 用于 find_all、scan 等

例如,puts "test 1 2 and test 3 4".scan(/\d/)会输出["1","2","3","4"]。

#/Hello*/ 匹配不了"HelloJack" 吧 代表 0 或多个字符。/Hello/匹配"Hello","HelloJack"

#1 楼 @OChan /Hello*/ 能匹配"HelloJack",但是不是你所想的那样, 这个/Hello*/表示匹配字符串依次顺序为'H'、'e'、'l'、'l'、'o',并在此之后有 0 个或者多个'o'"HelloJack"自然符合以上条件

ps:已通过Rubular验证

#2 楼 @ywjno 恩,我以为他给出的例子是 match 的内容。

/\d/后面加 u 是什么意思

请问,剔除一串字符串中非数字的正则表达式怎么写?

如何匹配出字符串中的“2013\/06\/05”,那位高人指点下

#5 楼 @hz_qiuyuanxin puts "1234abcdeffg_+--239-".scan(/\d/).join(",").delete(",").to_i

#4 楼 @aisf unicode 编码方式

"/([A-Z]\d){5}/匹配首位是大写字母,后面 4 个是数字的字符串" 这句话匹配"A12345"? 还是"A1A1A1A1A1dfghj"

这篇文章讲的啥玩意。。。。

You need to Sign in before reply, if you don't have an account, please Sign up first.