第14章            正则表达式(Regexp)类

建立正则表达式对象

用“//”括住正则表达式的样式

用类方法建立对象

“Regexp.new(str)”

以“%r”开头的写法。当正则表达式内部用到“/”字符的时候,改用“%r”会比较方便。如:

%r(样式), %r<样式>, %r|样式|, %r!样式!

 

正则表达式的样式与匹配

语法: 正则表达式 =~ 字符串

不成立时会返回nil,成立时会返回字符串中与样式匹配成功的起始位置。

 

简单匹配

正则表达式里的英文字母和数字,只会单纯地区匹配字符串里是否包含相同的文字。

样式:/ABC/

匹配:”ABC”, “ABCD”, “123ABC”

匹配行首行尾

“^”表示“与行首匹配成功的样式”, 而“$”则表示“与行尾匹配成功的样式”。

样式:/^ABC$/ 匹配:”ABC”

不匹配:”ABCD”, “123ABC”

与“^”和“$”匹配的是行头和行尾,而非字符串的头和字符串的尾。字符串头的匹配字符是“\A”,字符串尾的匹配字符是“\Z”。

匹配字符范围

想在多个字符里选一的情况,可用“[]”括起来

([]里没有顺序性)

  1. 指定较大范围时,可在“[]”里使用“-”号
  2. “-”写在“[]”内的最后面时,则指“-”这个符号本身。
  3. 在[]的最前面使用“^”,表示反向匹配

样式:/[ABC]/, /[CBA]/

匹配: A或B或C

样式:/[A-Za-z]/

匹配:所有英文字母

样式:/[A-Za-z_-]/

匹配:所有英文字母与“_”和“-”

样式:/[^ABC]/

匹配:A、B、C以外的字符

匹配任意字符

用“.”表示,可用于:

  1. 想要指定字数时,如/^…$/只会与刚好三个字的一行匹配成功。
  2. 配合“*”等转义字符使用。

样式:/A.C/

匹配:”ABC”, “12A3C45”

不匹配:”AC”, “abc”

转义字符

\s

表示空白,会与空白字符(0x20)、定位字符、换行字符、换页字符匹配成功。

\d

与0~9之间的数字匹配成功

\w

与英文字母及数字匹配成功

\A

与字符串前端匹配成功

样式:/\AABC/ 匹配:”ABC”, “ABCDE”

不匹配:/012ABC/

\Z

与字符串末端匹配成功

在“\”后接上“^”、“$”、“[”这些字母、数字以外的转义字符时,这些字符就不再具备转义字符的效用了,而可以去匹配这些字符本身。

样式:/\^ABC/  不匹配:”ABC“

重复出现匹配

“*”:出现0次及以上

“+”:出现1次及以上

“?”:出现0次或1次

最短匹配

用来匹配反复0次及以上的“*”与反复1次及以上的“+”,会尽可能匹配出最长的结果。如果只想比较出符合样式最短的部分(即反复后面的样式第一次出现的位置),则可用转义字符

“*?”: 出现0次及以上,但取最短的结果

“+?”: 出现1次及以上,但取最短的结果

匹配多个字符构成的字符串

用“()”

 

选择匹配

用“|”

样式:/^(AB|CD)+$/

匹配:”ABCD”

不匹配:”ABCABCAB”

在建立正则表达式时,想要忽略所有转义字符,可使用quote方法。

re1 = Regexp.new(“abc*def”)

re2 = Regexp.new(Regexp.quote(“abc*def”))

p (re1 =~ “abc*def”)     #=> nil

p (re2 =~ “abc*def”)     #=> 0

             

 

正则表达式的选项

选项字符

选项常数

意义

s

 

视为Shift_JIS匹配

e

 

视为EUC-JP匹配

u

 

视为UTF-8匹配

n

 

视为单字节文字匹配

i

IGNORECASE

匹配时忽略大小写

x

 

匹配时忽略样式里的空白

m

MULTILINE

多行匹配

o

EXTENED

样式内嵌表达式只做一次

使用Regexp.new方法建立对象时,选项常数可以传入第2个实参,而选项字符串则可以传入第3个实参。当第2个实参想指定不只一个选项时,可以使用“|”。

Regexp.new(“Ruby语言”, Regexp.IGNORECASE | Regexp.MULTILINE, “s”)

 

回溯参照

正则表达式的功能并不是只用来检查是否匹配成功。还有另外一个作用是回溯参照。所谓回溯参照,是取出字符串中匹配成功部分的一部分的功能。与正则表达式中“()”所括住的部分匹配成功的字符串,可以通过$1、$2这些形如“$数字”的变量取出。

/(.)(\d\d)+(.)/ =~ “123456”

p $1   #=> “1”

p $2   #=> “45”

p $3   #=> “6”

/(.)(?:\d\d)+(.)/ =~ “123456”

p $1   #=> “1”

p $2   #=> “6”

“()”同时也兼具并列多个样式在一起的功能。为防止混淆,若只要求并列样式,而不需要使用回溯参照的时候,可以写成“(?:)”。

/C./ =~ “ABCDEF”

p $`    #=> “AB”

p $&   #=> “CD”

p $’    #=> “EF”

除了“$数字”外,还有“$`”、“$&”、“$’”这3个变量也会储存匹配的结果。这3个变量的内容分别是“匹配成功部分左边的字符串”、“匹配成功部分的整个字符串”、“匹配成功部分右边的字符串”。

 

sub方法与gsub方法

sub与gsub方法都需要两个实参,第1个实参要指定想要匹配的正则表达式样式,而第2个实参则传入想要取代匹配成功出的字符串。sub方法只会取代第一个匹配成功处的字符串,而gsub方法则会取代所有匹配成功处的字符串。

sub与gsub方法还有加上“!”版本的方法,使用此版本,会直接取代方法的接收者这个字符串对象的内容。

str = “abc  def  g    hi”

p str.sub(/\s+/, ‘ ‘)    #=> “abc def  g    hi”

p str.gsub(/\s+/, ‘ ’)   #=> “abc def g hi”

示例:将连续出现的空白字符取代成一个空白

str = “abracatabra”

nstr = str.sub(/.a/) {|matched|

   ‘<’+matched.upcase+’>’

}

p nstr    #=> “ab<RA>catabra”

str = “abracatabra”

nstr = str.gsub(/.a/) {|matched|

   ‘<’+matched.upcase+’>’

}

p nstr    #=> “ab<RA><CA><TA>b<RA>”

sub方法与gsub方法也可以传入区块

 

scan方法

能够匹配到字符串里所有符合样式的部分 ,但不会进行取代的操作,只会获取而已。

“abracatabra”.scan(/.a/) {|matched|

   p matched

 }

输出:

“ra”

“ca”

“ta”

“ra”

“abracatabra”.scan(/(.)(a)/) {|matched|

   p matched

 }

输出:

[“r”, “a”]

[“c”, “a”]

[“t”, “a”]

[“r”, “a”]

当正则表达式内使用到“()”时,则匹配成功的部分会以数组的形式传入区块。

“abracatabra”.scan(/(.)(a)/) {|a, b|

   p matched

 }

输出:

“r-a“

“c-a“

“t-a“

“r-a“

在区块里指定与“()”的数量一样多的变量时,则不会传入数组,而直接依序分别指定给每个变量。

p “abracatabra”.scan(/.a/)    #=> [“ra”, “ca”, “ta”, “ra”]

没有指定区块时,scan方法会返回匹配成功的字符串的数组。

 

示例

匹配URL的简单写法

str = http://www.ruby-lang.org/ja/

%r|http://([^/]*)/| =~ str

print “server address: ”  $1, “\n”

输出:server address: www.ruby-lang.org

 

使用正则表达式取得服务器地址以外的部分

%r|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|

这是RFC2396“uniform Resource Identifiers (URL): Generic Syntax”这个URL一般写法规格文件里所提供的正则表达式。以这个样式进行匹配的话,“HTTP”之类的协议名会存放在$2,服务器地址会存放在$4、路径部分会存放在$5、查询部分会存放在$7、而区段部分会存放在$9。

如: http://www.example.co.jp/foo/?name=bar#baz

“http”是协议名,“www.example.co.jp”是主机地址,“/foo/”是路径,“name=bar”是查询,“baz”时区段名称。

 

正则表达式圣书<Mastering Regular Expression Third Edition>(Jeffrey E.F.Friedll著)