Ruby way 第三章学习『正则表达式』

        正则表达式历史悠久,功能强大,现代编程语言中少不了它的影子,但功能强度不大一样。Ruby把正则表达式在自身发挥的淋漓尽致 。

        刚学习正则表达式,看起来会觉得语法比较晦涩,等上手了呢,就会明白它的精髓。在这里,也不细讲正则表达式的语法问题了,只讲它在ruby中的使用。在ruby中,一个通常的正则表达式会是例如如下样子的:

/Ruby/

/[Rr]uby/

%r{xyz$}

%|[0-9]*|

等等...

而在ruby中,正则表达式有4种修饰符:

i       忽略大小写

o     只执行一次替换操作

m    多行匹配

x      使用扩展了的正则表达式语法(可以使用正则表达式的注释之类)

 

编译正则表达式
=========================================
可以使用Regexp.compile方法(和使用Regexp.new是一样的效果)来编译正则表达式。

Regexp.compile方法的第一个参数可以是一个字符串或则是一个正则表达式
(如果是一个正则表达式,并且它后面带了选项,则编译后,选项将不会出现在新的正则表达式中。)
 p1 = Regexp.compile("^foo.*")   # 结果: /^foo.*/
 p2 = Regexp.compile(/bar$/i)    # 结果:/bar/

如果要设置第二个参数,那么它的值可以是以下几个:
 Regexp::EXTENDED
 Regexp::IGNORECASE
 Regexp::MULTILINE

例如:
 p3 = Regexp.compile(/bar/, Regexp::IGNORECASE)

你如果你想同时使用他们之中的多个,则可以这样:
 options = Regexp::MULTILINE || Regexp::IGNORECASE
 pat4 = Regexp.compile("^foo", options)


它的第三个参数,是用来设置语言编码的,可以有如下值:
"N" or "n" #表示 None
"E" or "e" #表示 EUC
"S" or "s" #表示 Shift-JIS
"U" or "u" #表示 UTF-8


也可以直接使用正则表达式字面量,不用使用Regexp.compile方法或Regexp.new方法:
p1 = /^foo.*/
p2 = /bar$/i



转义正则表达式中的特殊字符
===========================================
使用Regexp.escape方法(别名方法是Regexp.quote),可以吧正则表达式中的特殊字符统统转义:
str1 = "[*?]"
str2 = Regexp.escape(str1)    # "\[\*\?\]"


访问正则表达式匹配后的数据引用
===========================================
在正则表达式中用使用括号的部分将被作为子匹配,有几中方式可以用来获取他们的引用:
1.比较“难看”方式:
使用特殊的全局变量,如:$1,$2....
str = "a123b45c678"
if /(a\d+)(b\d+)(c\d+)/ =~ str
  puts "Matches are: '#$1', '#$2', '#$3'"      # 打印: Matches are: 'a123', 'b45', 'c768'
end

我们来看下下面这段程序:
str = "a123b45c678"
str.sub(/(a\d+)(b\d+)(c\d+)/, "1st=#$1, 2nd=#$2, 3rd=#$3")   
# 结果: "1st=, 2nd=, 3rd="

为什么会结果是空呢?其实,上面的程序等同与下面的程序:
str = "a123b45c678"
s2 = "1st=#$1, 2nd=#$2, 3rd=#$3"
reg = /(a\d+)(b\d+)(c\d+)/
str.sub(reg,s2)
# 结果: "1st=, 2nd=, 3rd="

看明白了吧。
在这种情况下,我们要使用类似:\1,\2...之类的形式来引用了。
str = "a123b45c678"
str.sub(/(a\d+)(b\d+)(c\d+)/, '1st=\1, 2nd=\2, 3rd=\3') 
#注意,要使用单引号,否则会被解释成转义字符,如果用双引号,则要把斜杠转义掉,如:\\1,\\2
# 结果:"1st=a123, 2nd=b45, 3rd=c768"

我们还可以使用Ruby的block来实现上面的功能:
str = "a123b45c678"
str.sub(/(a\d+)(b\d+)(c\d+)/)  { "1st=#$1, 2nd=#$2, 3rd=#$3" }
# 结果: "1st=a123, 2nd=b45, 3rd=c678"

如果你想在匹配的时候跳过一个组的抓取,则可以使用(?: )语法:
str = "a123b45c678"
str.sub(/(a\d+)(?:b\d+)(c\d+)/, "1st=\\1, 2nd=\\2, 3rd=\\3")
# 结果:"1st=a123, 2nd=c678, 3rd="


以上的方式看起来很方便,不过,有的人会觉得它们看起来太杂乱,不好看,所以,还有以下方式来获取子匹配的引用:
pat = /(.+[aiu])(.+[aiu])(.+[aiu])(.+[aiu])/i
refs = pat.match("Fujiyama")

refs.to_a.each do |x|
  print "#{x}\n"
end

match方法将返回一个MatchData对象。

MatchData有begin和end两个方法,用来获取匹配结果在原字符串中的起始和结束位置
str = "alpha beta gamma delta epsilon"
pat = /(b[^ ]+ )(g[^ ]+ )(d[^ ]+ )/

refs = pat.match(str)

# "beta "
p1 = refs.begin(1)         # 6
p2 = refs.end(1)           # 11

# "gamma "
p3 = refs.begin(2)         # 11
p4 = refs.end(2)           # 17

# "delta "
p5 = refs.begin(3)         # 17
p6 = refs.end(3)           # 23

# "beta gamma delta"
p7 = refs.begin(0)         # 6
p8 = refs.end(0)           # 23


和begin,end方法相似的是offset方法,它返回一个数组,包括了匹配的起始和结束位置:
range0 = refs.offset(0)    # [6,23]
range1 = refs.offset(1)    # [6,11]
range2 = refs.offset(2)    # [11,17]
range3 = refs.offset(3)    # [17,23]


还有两个方法,pre_match和post_match,用来获取当前匹配结果的前一个和后一个匹配结果:
before = refs.pre_match    # "alpha "
after  = refs.post_match   # "epsilon"



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值