正在表达式与字符串的操作
要在高级层面处理字符串,必须学会正则表达式,其实,正则表达式就是搜索查询,ruby在对某个很长的字符串运
行该查询,就能得到你期望的内容,这样看来,正则表达式也是一个字符串,代表规则的字符串,按照这种规则可
指定的对象上找出相匹配的的元素。
替换
对于字符串,这是经常的操作之一,把某些内容替换为其它内容,如:
puts "foobar".sub('bar','foo')
irb(main):071:0> puts "foobar".sub('bar','foo')
foofoo
=> nil
本例中,使用对字符串调用的sub方法,该方法把第一次遇到的‘bar’替换为‘foo’,替换的结果为foofoo。
sub方法只对发现的第一个匹配文本做一次替换,而gsub方法则对所有匹配文本进行多次替换,如:
irb(main):072:0> puts "This is a test".gsub('i','')
Ths s a test
=> nil
这里把所有字母‘i’替换成空字符串,只匹配字符‘i’ 不是真正的正则表达式,如,把字符串开头两个字符替
换成'Hello':
irb(main):073:0> x = "This is a test"
=> "This is a test"
irb(main):074:0> puts x.sub(/^../ , 'Hello')
Hellois is a test
=> nil
本例中,使用sub的方法进行了单个替换,传递给sub方法的第一个参数不是字符串,而是一个正则表达式,斜
杠"/"用于表示正则表达式的开头和结尾。在正则表达式^..中,^称为锚,表示正则表达式将从字符中的任一行开
头进行匹配。至于..,每个点都表示"任何字符",综上可知,/^../表示”某行开始的开头两个字符“,所以“Th
”被替换成了Hello。我们如果想将行尾的两个字符替换成Hello,怎么办呢?与^相反,$就是从行尾进行匹配的,
直接将第一个参数改为:/..$/即可实现。
使用正则表达式进行迭代
如果想访问字符串的各个部分,应该怎么办?scan正是所需要的迭代子方法:
“xyz”.scan(/./) {|letter| puts letter}
irb(main):077:0> "xyz".scan(/./) {|letter| puts letter}
x
y
z
=> "xyz"
在字符串中难免出现空格,如果只匹配字母或数字,正则表达式中使用\w即可,\w代表“字母表中的任何字符或下
划线”,如下:
irb(main):081:0> "This is a test".scan(/\w\w/) { |x| puts x}
Th
is
is
te
st
=> "This is a test"
正则表达式中基本的特殊字符和符号
^ 用于行开始的锚
$ 用于行结束的锚
\A 用于字符开始的锚
\Z 用于字符结束的锚
. 任意字符
\w 任何字母、数字或下划线
\W 不匹配\w的任何内容
\d 任何数字
\D 不匹配\d的内容
\s 空白(空格、制表符、换行符等)
\S 非空白(任何可见字符)
正则表达式字符和子表达式修饰符
* 匹配零次或多次前面紧跟的字符,并尽量多地匹配
+ 匹配一次或多次前面紧跟的字符,并尽量多地匹配
*? 匹配零次或多次前面紧跟的字符,并尽量少地匹配
+? 匹配一次或多次前面紧跟的字符,并尽量少地匹配
? 要么匹配一次,要么全不匹配前面紧跟的字符
{x} 匹配x次前面紧跟的字符
{x,y} 匹配最少x次、最多y次前面紧跟的字符
关于正则表达式,需要理解字符类别(character classes),这些字符类别让可以针对特定字符集合进行匹配。
例如,可以扫描字符串中所有元音字符:
“This is a test”.scan(/[aeiou]/) { |x| puts x}
匹配任何字符,可以在[]指定字符范围,如[a-m]
irb(main):002:0> "This is a test".scan(/[a-m]/) { |x| puts x }
h
i
i
a
e
=> "This is a test"
匹配查询
做替换和从字符串中解析某些文本是很有用的,但有时我们只想检查某个字符串是否匹配所选择的模式。例如,可
能想快速得知字符串是否包含元音字母
puts “String has vowels”if "This is a test" =~ /[aeiou]/
irb(main):001:0> puts "String has vowels" if "This is a test" =~ /[aeiou]/
String has vowels
=> nil
=~是另一种运算符,即匹配查询运算符。如果字符串与后面的正则表达式相匹配,则该表达式结果为true。也可做
相反的操作:
puts “String cotains no digits”unless "This is a test" =~/[0-9]/ 其含义是除非0到9的数字匹配测试字
符串,否则就告诉用户,字符串中没有数字。
irb(main):001:0> puts "String contains no digits" unless "This is a test" =~ [0-9]
String contains no digits
=> nil
还可以使用String类提供的match的方法,=~是根据正则表达式是否匹配字符串,返回true 或false,而match方
法则提供了许多更强大的能力,如:
puts "String has vowels" if "This is a test".match(/[aeiou]/)
该例子看起来与前面的例子几乎一样,但match方法不需要用正则表达式作为参数,它把提供给它的任何字符串都
转换成正则表达式,因此也可以这么写:
puts "String has vowels" if "This is a test".match("[aeiou]")
如果正则表达式由用户提供,或从文件及其他外部来源载入,这种功能是非常有用的。
在正则表达式中,如果其中一部分由括号包围,则该部分正则表达式所匹配的数据可以单独使用,与剩余的其它数
据不相干。match方法让你可以访问这些数据:
irb(main):001:0> x = "This is a test".match(/(\w+) (\w+)/)
=> #
irb(main):002:0> puts x[0]
This is
=> nil
irb(main):003:0> puts x[1]
This
=> nil
irb(main):004:0> puts x[2]
is
=> nil
match方法返回MatchData对象,该对象的访问方法与数组类似。第一个元素包含整个正则表达式所匹配的数据,但
每个后续元素都只包含正则表达式每块单元所匹配的内容。在本例中,第一块(\w+)匹配This,第二块(\w+)匹配
is。