`
simohayha
  • 浏览: 1395581 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

ruby way之正则表达式之一

    博客分类:
  • ruby
阅读更多
在ruby中内置了正则表达式,如果你的ruby版本是1.9或者更后面的版本的话,你的正则表达式引擎将会是一个叫做Oniguruma的东西。这是一个新的引擎,代替了1.8版本中的这则表达式引擎,我们后面会介绍到它。

1编译正则表达式:
正则表达式能够使用Regexp.compile 方法进行编译(这个方法同Regexp.new方法是同义的),
参数可以是一个字符串或者一个正则式(这边要注意一个问题,如果参数是正则式的话,他所附带的参数将会被传播,你可以不用指定后续的第二个参数,这个马上就会看到),看下面的例子:
test1=Regexp.compile("Bar");
test=Regexp.compile(/Bar/i);  #忽略大小写
puts test1.match("bar") #nil
puts test.match("bar") #bar

第二个参数,如果存在的话可以是由||连接起来的 下面几个值Regexp::EXTENDED, Regexp::IGNORECASE,  Regexp::MULTILINE。第二个参数如果是true代表大小写不敏感,否则代表大小写敏感。可是如果参数是一个正则式的话,第二个参数将会被忽略.

options = Regexp::MULTILINE || Regexp::IGNORECASE
pat3 = Regexp.compile("^foo", true)
pat4 = Regexp.compile(/Bar/, Regexp::IGNORECASE)

puts pat3.match("Doo")      #这边大小写不敏感,所以返回doo
puts pat4.match("bar")        #这边将会返回nil,因为第二个参数被忽略了,ruby解释器会给你提醒的..


第三个参数启用对正则表达式的多字节支持。同样的如果使用正则式,它将会被忽略.
"N" or "n" means None
"E" or "e" means EUC
"S" or "s" means Shift-JIS
"U" or "u" means UTF-8


最后,我们还可以直接使用//来定义正则表达式,而不需要任何compile方法。。

pat1 = /^foo.*/
pat2 = /bar$/i


2 转义特殊字符

我们可以使用Regexp.escape 方法来转义特殊字符,转义的返回值就是所能匹配的正则表达式,也就是说 Regexp.new(Regexp.escape(str)) =~str一定返回true.

str1 = "[*?]"
str2 = Regexp.escape(str1)  # "\[\*\?\]"
puts str1 =~Regexp.new(str2)   #返回0


3使用锚

一个锚是一个特殊的匹配一个字符串中的位置的表达式。

最简单的锚就是 ^和$,它们分别匹配一个字符串的开始或者结尾的位置.

strings  = "abcXdefXghi"
puts strings =~/def/   #4
puts strings =~/abc/     # 0
puts strings =~/ghi/     # 8
puts strings =~/^def/    # nil
puts strings =~/def$/  # nil
puts strings =~/^abc/   # 0
puts strings =~/ghi$/    # 8


可是这边小小的撒了个谎,其实^和$并不是真正的匹配字符串的开始或结尾,它们会分隔多行,也就是说如果有多行的话,他们会匹配多个开始和结尾,我们看下面的例子:

strings  = "abc\ndef\nghi"  #这边我们加入了几个回车


puts strings =~/def/   #4
puts strings =~/abc/     # 0
puts strings =~/ghi/     # 8
puts strings =~/^def/    # 4   #它会把新的一行的第一个字符匹配
puts strings =~/def$/  # 4
puts strings =~/^abc/   # 0
puts strings =~/ghi$/    # 8


可是我们这边有两个真正的匹配字符串的开始或者结尾的锚,他们是 \A 和 \Z :
string  = "abc\ndef\nghi"
puts string =~/\Adef/    # nil
puts string =~/def\Z/   # nil
puts string =~/\Aabc/      # 0
puts string =~/ghi\Z/     # 8


这边还有一个\z(小z),它和\Z不同的是,它不会匹配最后一个回车。:

string  = "abc\ndef\nghi"
puts string  =~ /ghi\Z/    # 8
puts string  =~/\Aabc/        # 0
puts string  =~/ghi\Z/     # 8
puts string  =~/ghi\z/   # 8
string << "\n"
puts string  =~/ghi\z/   # nil #由于有最后一个回车,因此这边不能匹配


还可以用\b来匹配单词的边界,或者\B匹配一个不是单词边界的位置..

str = "this is a test"
puts str.gsub(/\b/,"|")      # "|this| |is| |a| |test|"
puts str.gsub(/\B/,"-")      # "t-h-i-s i-s a t-e-s-t"


4 使用量词符号

正则表达式中很大的一部分就是表示可选的字符和字符串重复.一个字符后面跟着一个问号,代表这个字符可以是1个或者0个:
pattern = /ax?b/
pat2    = /a[xy]?b/
puts "ab" =~pattern      # 0
puts  "acb" =~pattern     # nil
puts  "axb" =~ pattern  # 0
puts "ayb" =~pat2 # 0
puts "acb" =~pat2 # nil


我们可以使用+来匹配一个或者多个字符:
pattern = /[0-9]+/
puts pattern =~ "1"         # 0
puts pattern =~ "2345678"   # 0


另外一个经常使用的匹配模式是,匹配0个或者多个,我们可以使用+和?的组合来实现:

pattern = /Huzzah(!+)?/   # Parentheses are necessary here
puts pattern =~ "Huzzah"       # 0
puts pattern =~ "Huzzah!!!!"   # 0


但是这里有一个更好的办法,那就是*号:

pattern = /Huzzah!*/      # * applies only to !
puts pattern =~ "Huzzah"       # 0
puts pattern =~ "Huzzah!!!!"   # 0


如果我们相匹配一个U.S. Social Security Number,我可以这样做:

ssn = "987-65-4320"
pattern = /\d\d\d-\d\d-\d\d\d\d/
puts pattern =~ ssn       # 0

#看起来很丑陋,我们其实可以使用更好的方法,那就是使用{}符号,它里面放一个数字#n,代表着一个字符重复n次:

pattern = /\d{3}-\d{2}-\d{4}/
puts pattern =~ ssn       # 0


逗号分隔符还可以被放进{},比如{start,end},其中start指的是最少的重复次数,end指的是最大的重复字数,其中start和end都是可选的,可是两个必须存在一个:
引用
/x{5}/        # 匹配 5 个x
/x{5,7}/      # 匹配 5到7 个x
/x{,8}/       #匹配 最多8 个x
/x{3,}/       #匹配最少 3个x


正则表达式的专用术语都是充满了人性化,比如greedy, reluctant, lazy, and possessive.

思索下面的代码,一个字符串
str = "Where the sea meets the moon-blanch'd land,"
我们只想匹配
"Where the", 可是经常会匹配到一个更大的子字符串"Where the sea meets the" 。:

str = "Where the sea meets the moon-blanch'd land,"
match = /.*the/.match(str)
puts  match[0]  # here the sea meets the


为什么会这样子呢?这是由于*是一个greedy匹配,也就是一个贪婪匹配,他总是匹配,他所能匹配的最长的字符串,如果我们要匹配"Where the",则我们可以这么做:

str = "Where the sea meets the moon-blanch'd land,"
match = /.*?the/.match(str)
puts match[0]  # "Where the" 


这边给* 后面加一个?就会生成一个非贪婪的匹配,这条规则对+和{m,n} 都是一样成立的,甚至对?他自己。

这边作者举不出{m,n}?和??的例子,说谁有好的例子可以告诉他..

5 Positive and Negative Lookahead(这个我也不知道怎么翻译...)

这个我觉得 Mastering.Regular.Expressions,讲的更好,我就按自己理解的说了:

这边有两个符号,一个是Positive lookahead也就是(?= ),还有一个Negative lookahead
也就是(?! )。这两个符号其实很容易理解,两个匹配的都是一个分界,而不是其他的,其中(?= )匹配的是括号里面字符的前面所匹配的那个点,比如 s="abc" (?=bc)匹配的就是a和bc之间的那个点. 而(! )恰恰相反,也就是非那个点。。

reg = /New World(?= Dictionary| Symphony)/
m1 = reg.match(s1)
puts m1.to_a[0]              # "New World"
m2 = reg.match(s2)
puts m2.to_a[0]              # "New World"
m3 = reg.match(s3)     
puts m3.to_a[0]           # nil


reg2 = /New World(?! Symphony)/
m1 = reg2.match(s1)
puts m1.to_a[0]              # "New World"
m2 = reg2.match(s2)
puts m2.to_a[0]              # nil
m3 = reg2.match(s3)     
puts m3.to_a[0]           # "New World"


6 访问后引用

每一个小括号里面的正则表达式都会有它自己的一个子匹配,他们能通过一些方法来得到这些子匹配,比如全局的变量 $1,$2等等。。:
str = "a123b45c678"
if /(a\d+)(b\d+)(c\d+)/ =~ str
  puts "Matches are: '#$1', '#$2', '#$3'"
  # 打印出: Matches are: 'a123', 'b45', 'c768' 
end


作者这里说象在sub,gsub方法里面$1之类的不能用,我的ruby是1.9 ,sub和gsub是可以用的:

str = "a123b45c678"
puts str.sub(/(a\d+)(b\d+)(c\d+)/, "1st=#$1, 2nd=#$2, 3rd=#$3") 
#打印出1st=a123, 2nd=b45, 3rd=c678

在sub和gsub方法中我们还可以使用\1 ..来替代$1:

str = "a123b45c678"
puts str.sub(/(a\d+)(b\d+)(c\d+)/, '1st=\1, 2nd=\2, 3rd=\3')
# "1st=a123, 2nd=b45, 3rd=c678"


注意我们这里使用的是单引号,这是因为双引号会把\1转义,如果要在双引号中使用\1,我们必须用\\1来替代:

str = "a123b45c678"
puts str.sub(/(a\d+)(?:b\d+)(c\d+)/, "1st=\\1, 2nd=\\2, 3rd=\\3")
# "1st=a123, 2nd=c678, 3rd="


在上面的例子中第二个匹配打印出来的是第三个,而第三个匹配,却是nil,注意,这边第二个括号,我们使用的是(?: )这个符号,这个会不捕捉他所匹配的子字符串,所以这里b45没有被打印出来.

$1这种标记虽然有时候看起来很好用,可是我们可以使用更面向对象一点的方,Regexp.match方法这个方法返回一个MatchData类,它包含所有的子匹配,我们可以把它转换成一个数组来取得所有的子匹配:

pat = /(.+[aiu])(.+[aiu])(.+[aiu])(.+[aiu])/i
# Four identical groups in this pattern
refs = pat.match("Fujiyama")
puts refs.to_a.each {|xx| print "#{xx}\n"}
# 打印出: ["Fujiyama","Fu","ji","ya","ma"]


我们还可以使用begin和end方法,来返回匹配的位移:

str = "alpha beta gamma delta epsilon"
#      0....5....0....5....0....5....
#      (for  your counting convenience)

pat = /(b[^ ]+ )(g[^ ]+ )(d[^ ]+ )/
# Three words, each one a single match
refs = pat.match(str)

# "beta "
puts p1 = refs.begin(1)         # 6  返回所经过的位移
puts p2 = refs.end(1)           # 11
# "gamma "
puts p3 = refs.begin(2)         # 11
puts p4 = refs.end(2)           # 17
# "delta "
puts p5 = refs.begin(3)         # 17
puts p6 = refs.end(3)           # 23
# "beta gamma delta"
puts p7 = refs.begin(0)         # 6
puts p8 = refs.end(0)           # 23


而offset方法返回一个2个元素的数组他分别是开始和结束的偏移量:

puts range0 = refs.offset(0)    # [6,23]
puts range1 = refs.offset(1)    # [6,11]
puts range2 = refs.offset(2)    # [11,17]
puts range3 = refs.offset(3)    # [17,23]


pre_match 和post_match方法返回当前匹配的前一个前面部分和后面部分.

puts before = refs.pre_match    # "alpha " 
puts after  = refs.post_match   # "epsilon"


刚好去除掉匹配的东西,留下的就是我们打印出来的..







分享到:
评论

相关推荐

    Addison Wesley The Ruby Way 2Nd Edition Oct 2006.pdf(英文版)

    3. **正则表达式引擎(Oniguruma)**:介绍了一种新的正则表达式处理引擎,提高了处理效率和灵活性。 4. **国际化(I18N)与消息目录**:探讨了如何使用Ruby进行国际化支持,包括消息目录的创建和管理。 5. **高级...

    Addison.Wesley.The.Ruby.Way.2nd.Edition.Oct.2006.chm

    Ruby的标准库非常丰富,书中会介绍一些常用的库,如Net::HTTP用于网络请求,JSON和YAML用于数据序列化,Regexp用于正则表达式匹配,以及Open3和PTY用于进程管理和交互。这些库大大扩展了Ruby的功能,使其在各种场景...

    the ruby way

    它覆盖了Ruby的基础语法、类和对象、模块、集合、文件和I/O、网络编程、正则表达式、线程和并发、元编程等方面,以及如何利用Gem进行项目开发。无论是初学者还是有经验的开发者,都能从中受益,提升Ruby编程技能。

    关于ruby的几本电子书

    它深入探讨了Ruby语言的各种特性,包括基础语法、面向对象编程、模块和类、异常处理、文件系统操作、网络编程以及正则表达式等。书中的例子丰富,旨在帮助读者理解并掌握Ruby的精髓,从而能以"Ruby Way"的方式来思考...

    Ruby语言教程&案例&相关项目资源.docx

    - **字符串处理**:提供丰富的字符串处理功能,如字符串插值、多行字符串、正则表达式等。 - **异常处理**:支持异常处理机制,能够捕获并处理程序运行时出现的异常情况。 #### 应用领域 - **Web开发**:Ruby最...

    pythonchallenge level2官方方法集

    更简单的正则表达式,正则表达式是处理字符串的强大工具,这里强调了其在解决特定问题时的简化应用。 #### 42. PHP Solution PHP解决方案,展示了PHP语言在Web开发领域解决问题的能力和灵活性。 #### 43. Another...

Global site tag (gtag.js) - Google Analytics