进行匹配

最简单的正则表达式(regular expression)几乎是一系列字符,例如 ‘abc’,你会感觉到它是一个字符串。只需简单的将这些字母放在两个正斜杠(forward-slash)分隔符之间 /abc/,就可以创建匹配 ‘abc’ 的正则表达式。你可以使用 =〜 运算符方法来测试匹配(match),如下所示:

regex0.rb
  1. puts( /abc/ =~ 'abc' ) #=> returns 0

如果匹配,则返回表示字符串中字符位置的整数。如果不匹配,则返回 nil

  1. puts( /abc/ =~ 'xyzabcxyzabc' ) #=> returns 3
  2. puts( /abc/ =~ 'xycab' ) #=> returns nil

你还可以在方括号之间指定一组字符,在这种情况下,将在字符串中匹配这组字符中的任何一个。例如,在这里,首先匹配到了 ‘c’,并返回该字符在字符串中的位置:

  1. puts( /[abc]/ =~ 'xycba' ) #=> returns 2

虽然我在上面的示例中使用了正斜杠分隔符,但还有其它方式可以定义正则表达式:你可以专门创建一个使用字符串初始化的新的 Regexp 对象,或者你可以在正则表达式之前使用 %r 并使用自定义分隔符 - 非字母数字字符 - 就像字符串一样(参见第 3 章)。在下面的示例中,我使用花括号分隔符:

regex1.rb
  1. regex1 = Regexp.new('^[a-z]*$')
  2. regex2 = /^[a-z]*$/
  3. regex3 = %r{^[a-z]*$}

上面的每一个,都定义了一个匹配全小写字符串的正则表达式(我将很快解释表达式的细节)。 这些表达式可用于测试这样的字符串:

  1. def test( aStr, aRegEx )
  2. if aRegEx =~ aStr then
  3. puts( "All lower case" )
  4. else
  5. puts( "Not all lower case" )
  6. end
  7. end
  8. test( "hello", regex1 ) #=> matches: "All lower case"
  9. test( "hello", regex2 ) #=> matches: "All lower case"
  10. test( "Hello", regex3 ) #=> no match: "Not all lower case"

要测试匹配(match),可以使用 if=〜 运算符:

if_test.rb
  1. if /def/ =~ 'abcdef'

如果匹配,则上面的表达式求值为 true(并返回一个整数);如果没有匹配则会计算为 false(并返回 nil):

  1. RegEx = /def/
  2. Str1 = 'abcdef'
  3. Str2 = 'ghijkl'
  4. if RegEx =~ Str1 then
  5. puts( 'true' )
  6. else
  7. puts( 'false' )
  8. end #=> displays: true
  9. if RegEx =~ Str2 then
  10. puts( 'true' )
  11. else
  12. puts( 'false' )
  13. end #=> displays: false

通常,尝试从字符串的最开头匹配某个表达式是有用的;字符 ^ 后跟匹配项用于指定这个(前缀匹配)。从字符串的末尾进行匹配也可能很有用;字符 $ 前置一个匹配项用于指定这个(后缀匹配)。

start_end1.rb
  1. puts( /^a/ =~ 'abc' ) #=> returns 0
  2. puts( /^b/ =~ 'abc' ) #=> returns nil
  3. puts( /c$/ =~ 'abc' ) #=> returns 2
  4. puts( /b$/ =~ 'abc' ) #=> returns nil

当字符串构成更复杂模式(pattern)的一部分时,从字符串的开头或结尾进行匹配会变得更有用。通常,这种模式会尝试匹配指定模式的零个或多个实例。* 字符用于表示其所遵循的模式的零个或多个匹配(matches)。形式上,这被称为“量词”(quantifier)。思考这个示例:

start_end2.rb
  1. puts( /^[a-z 0-9]*$/ =~ 'well hello 123' )

这里,正则表达式在方括号之间指定了字符范围。此范围包括所有小写字符,a-z,所有数字,0-9,加上空白字符(即此表达式中 “z” 和 “0” 之间的空格)。^ 字符表示必须从字符串的开头进行匹配,范围之后的 * 表示必须与范围中的字符进行零次或多次匹配,而 $ 字符表示必须匹配到字符串的末尾。换句话说,此模式(pattern)仅匹配从字符串的起始位置到结尾处包含小写字符,数字和空格的字符串:

  1. puts( /^[a-z 0-9]*$/ =~ 'well hello 123' ) # match at 0
  2. puts( /^[a-z 0-9]*$/ =~ 'Well hello 123' ) # no match due to ^ and uppercase 'W'

实际上,这个模式也会匹配一个空字符串,因为 * 表示可以接受零个或多个匹配:

  1. puts( /^[a-z 0-9]*$/ =~ '' ) # this matches!

如果要排除空字符串,请使用 +(以匹配模式的一个或多个匹配项):

  1. puts( /^[a-z 0-9]+$/ =~ '' ) # no match

尝试使用 start_end2.rb 中的代码,了解更多示例,其中 ^$*+ 可以与范围组合以创建各种不同的匹配模式(match-patterns)。

你可以使用这些技术来确定字符串的特定特征,例如给定字符串是大写的,小写的还是大小写混合的:

regex2.rb
  1. aStr = "HELLO WORLD"
  2. case aStr
  3. when /^[a-z 0-9]*$/
  4. puts( "Lower case" )
  5. when /^[A-Z 0-9]*$/
  6. puts( "Upper case" )
  7. else
  8. puts( "Mixed case\n" )
  9. end

通常,正则表达式用于处理磁盘上文件中的文本。例如,假设你希望在 Ruby 文件中显示所有单行(full-line)注释,但省略所有代码或行内注释。你可以通过尝试从每行的开头匹配(^)零个或多个空格字符(空格字符由 \s 表示)直到注释字符('#'):

regex3a.rb
  1. # displays all the full-line comments in a Ruby file
  2. File.foreach( 'regex1.rb' ){ |line|
  3. if line =~ /^\s*#/ then
  4. puts( line )
  5. end
  6. }