参考:
Regexp 类:
1、使用 /.../ 或者 %r{} 创建,或者 Regexp.new
- /hay/ =~ 'haystack' #=> 0 # 返回值为匹配字符所在位置,或者 nil
- /y/.match('haystack') #=> #<MatchData "y"> # 返回值为 MatchData 或者 nil
2、元字符有:
(
, )
, [
, ]
, {
, }
, .
,?
, +
, *
. 3、模板的行为类似于双引号,可以加入转义符
- /\s\u{6771 4eac 90fd}/.match("Go to 東京都")
- #=> #<MatchData " 東京都">
同样可以嵌入 #{...}
- place = "東京都"
- /#{place}/.match("Go to 東京都")
- #=> #<MatchData "東京都">
4、[0-9a-f] 、支持 && 操作符:取两个表达式的交集
- /[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))
- # 等级于如下表达式
- /[abh-w]/
5、
- /./ - 任意字符,不包括回车换行
- /./m - 任意字符,包括回车换行,类似于 perl 的 s ( m 修饰符启用多行模式,就是将多行当一行处理)
- /\w/ - 等价于 ([a-zA-Z0-9_])
- /\W/ - 同 \w 正相反 ([^a-zA-Z0-9_])
- /\d/ - 数字 ([0-9])
- /\D/ - 非数字 ([^0-9])
- /\h/ - 16进制,等价于 ([0-9a-fA-F])
- /\H/ - 非16进制 ([^0-9a-fA-F])
- /\s/ - 空白字符,包括回车换行: /[ \t\r\n\f]/
- /\S/ - 非空白字符: /[^ \t\r\n\f]/
6、
- /[[:alnum:]]/ - 等价于 [0-9a-zA-z]
- /[[:alpha:]]/ - 等价于 [a-zA-Z]
- /[[:blank:]]/ - 空格或 tab
- /[[:cntrl:]]/ - ctrl
- /[[:digit:]]/ - [0-9]
- /[[:graph:]]/ - 非空白字符 (excludes spaces, control characters, and similar)
- /[[:lower:]]/ - 等价于 [a-z]
- /[[:print:]]/ - Like [:graph:], but includes the space character
- /[[:punct:]]/ - Punctuation character
- /[[:space:]]/ - 空白字符 ([:blank:], 换行,回车, 等.)
- /[[:upper:]]/ - 大写字符,[A-Z]
- /[[:xdigit:]]/ - 16进制数,等价于 [0-9a-fA-F] (i.e., 0-9a-fA-F)
- /[[:word:]]/ - A character in one of the following Unicode general categories Letter, Mark, Number, Connector_Punctuation
- /[[:ascii:]]/ - A character in the ASCII
7、匹配次数
- * - >= 0
- + - >= 1
- ? - 0 or 1
- {n} - = n
- {n,} - >=n
- {,m} - <=m
- {n,m} - n < ... < m
8、结果捕获,使用 (..)
a、
- # 'at' is captured by the first group of parentheses, then referred to
- # later with \1
- /[csh](..) [csh]\1 in/.match("The cat sat in the hat")
- #=> #<MatchData "cat sat in" 1:"at">
- # Regexp#match returns a MatchData object which makes the captured
- # text available with its #[] method.
- /[csh](..) [csh]\1 in/.match("The cat sat in the hat")[1] #=> 'at'
b、
对捕获结果命名,使用
(?<
name>)
或者 (?'
name')
- /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")
- => #<MatchData "$3.67" dollars:"3" cents:"67">
- /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")[:dollars] #=> "3"
c、
引用上述匹配结果,使用
\k<
name>
- /(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
- #=> #<MatchData "ototo" vowel:"o">
注意:不能同时使用命名引用和数字引用,即不能同时使用
\k<
name>
和 $1 等方式
d、如果 regexp 位于表达式,或者 =~ 操作符左侧,ruby 会生成一个本地变量,保存结果,可以直接使用
- /\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
- dollars #=> "3"
9、分组
a、
(..) 即分组,其后可跟重复量词
- # The pattern below matches a vowel followed by 2 word characters:
- # 'aen'
- /[aeiou]\w{2}/.match("Caenorhabditis elegans") #=> #<MatchData "aen">
- # Whereas the following pattern matches a vowel followed by a word
- # character, twice, i.e. <tt>[aeiou]\w[aeiou]\w</tt>: 'enor'.
- /([aeiou]\w){2}/.match("Caenorhabditis elegans")
- #=> #<MatchData "enor" 1:"or">
b、
(?:
…) 表示分组,但不捕获结果。
- # The group of parentheses captures 'n' and the second 'ti'. The
- # second group is referred to later with the backreference \2
- /I(n)ves(ti)ga\2ons/.match("Investigations")
- #=> #<MatchData "Investigations" 1:"n" 2:"ti">
- # The first group of parentheses is now made non-capturing with '?:',
- # so it still matches 'n', but doesn't create the backreference. Thus,
- # the backreference \1 now refers to 'ti'.
- /I(?:n)ves(ti)ga\1ons/.match("Investigations")
- #=> #
c、原子分组
....
没怎么看懂....
- # The <tt>" in the pattern below matches the first character of
- # the string, then .* matches Quote"</i>. This causes the
- # overall match to fail, so the text matched by <tt>.*</tt> is
- # backtracked by one position, which leaves the final character of the
- # string available to match <tt>"
- /".*"/.match('"Quote"') #=> #\"Quote\"">
- # If <tt>.*</tt> is grouped atomically, it refuses to backtrack
- # <i>Quote", even though this means that the overall match fails
- /"(?>.*)"/.match('"Quote"') #=> nil
参考:http://blog.donews.com/maverick/archive/2005/11/28/641232.aspx
(刚刚发现这个地址是《精通正则表达式》译者的博客,这本书还没看完,汗颜!)
这篇文章讲得很清楚:
简单的说,Atomic Grouping的主要功能便是取消回溯,提高效率——如果匹配成功,它与普通的grouping并无区别,但是如果匹配失败,所有位于Atomic Grouping中的状态会全部失效。 一般正则表达式为贪婪匹配,或者非贪婪匹配。在匹配不成功时,会进行回溯,不断测试各个分支。原子分组就是将 (?> pat) 中的 pat 匹配作为一个原子操作,(不管贪婪还是非贪婪),要么成功,要么失败,一锤子买卖,不做回溯。
10、子表达式引用 : Subexpression Calls
通过
\g<
name>
语法 对 (?) 匹配到的内容进行反向引用。也可以通过数字来进行,类似于前面的 $1。
- # Matches a <i>(</i> character and assigns it to the <tt>paren</tt>
- # group, tries to call that the <tt>paren</tt> sub-expression again
- # but fails, then matches a literal <i>)</i>.
- /\A(?<paren>\(\g<paren>*\))*\z/ =~ '()'
- /\A(?<paren>\(\g<paren>*\))*\z/ =~ '(())' #=> 0
- # ^1
- # ^2
- # ^3
- # ^4
- # ^5
- # ^6
- # ^7
- # ^8
- # ^9
- # ^10
- Matches at the beginning of the string, i.e. before the first character.
- Enters a named capture group called paren
- Matches a literal (, the first character in the string
- Calls the paren group again, i.e. recurses back to the second step
- Re-enters the paren group
- Matches a literal (, the second character in the string
- Try to call paren a third time, but fail because doing so would prevent an overall successful match
- Match a literal ), the third character in the string. Marks the end of the second recursive call
- Match a literal ), the fourth character in the string
- Match the end of the string
11 、选择性匹配
两个表达式通过 | 关联,表示任意匹配其中一个即可,例子:
- /\w(and|or)\w/.match("Feliformia") #=> #<MatchData "form" 1:"or">
- /\w(and|or)\w/.match("furandi") #=> #<MatchData "randi" 1:"and">
- /\w(and|or)\w/.match("dissemblance") #=> nil
12、字符属性 : Character Properties
东西太多,只举几个例子:
- /\p{Alnum}/ - Alphabetic and numeric character
- /\p{Alpha}/ - Alphabetic character
- /\p{Blank}/ - Space or tab
- /\p{Cntrl}/ - Control character
- /\p{Digit}/ - Digit
- /\p{Graph}/ - Non-blank character (excludes spaces, control characters, and similar)
- /\p{Lower}/ - Lowercase alphabetical character
- /\p{Print}/ - Like \p{Graph}, but includes the space character
- /\p{Punct}/ - Punctuation character
- /\p{Space}/ - Whitespace character ([:blank:], newline, carriage return, etc.)
- /\p{Upper}/ - Uppercase alphabetical
- /\p{XDigit}/ - Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
- /\p{Word}/ - A member of one of the following Unicode general category Letter, Mark,
13、锚
^ - 匹配行首
$ - 匹配行尾
\A - 匹配字符串的开头
\Z - 匹配字符串的结尾. 如果字符串结尾是回车换行,只匹配回车换行前。
\z - 匹配字符串的结尾
\G - Matches point where last match finished
\b - Matches word boundaries when outside brackets; backspace (0x08) when inside brackets
\B - Matches non-word boundaries
(?=pat) - Positive lookahead assertion: ensures that the following characters match pat, but doesn't include those characters in the matched text
(?!pat) - Negative lookahead assertion: ensures that the following characters do not match pat, but doesn't include those characters in the matched text
(?<=pat) - Positive lookbehind assertion: ensures that the preceding characters match pat, but doesn't include those characters in the matched text
(?
- # If a pattern isn't anchored it can begin at any point in the string
- /real/.match("surrealist") #=> #
- # Anchoring the pattern to the beginning of the string forces the
- # match to start there. 'real' doesn't occur at the beginning of the
- # string, so now the match fails
- /\Areal/.match("surrealist") #=> nil
- # The match below fails because although 'Demand' contains 'and', the
- pattern does not occur at a word boundary.
- /\band/.match("Demand")
- # Whereas in the following example 'and' has been anchored to a
- # non-word boundary so instead of matching the first 'and' it matches
- # from the fourth letter of 'demand' instead
- /\Band.+/.match("Supply and demand curve") #=> #<MatchData "and curve">
- # The pattern below uses positive lookahead and positive lookbehind to
- # match text appearing in <b></b> tags without including the tags in the
- # match
- /(?<=<b>)\w+(?=<\/b>)/.match("Fortune favours the bold")
- #=> #<MatchData "bold">
14、修饰符
/pat/i - 忽略大小写
/pat/m - 允许 . 匹配回车换行;同 perl 的 s 修饰符类似。
/pat/x - 忽略空白字符和注释;模板可以写的较为优美,易读。
/pat/o - 仅对 #{} 做一次解析;具体用法还没搞清楚。
i, m, 和x 修饰符可以用在子表达式中。通过 (?) 语法进行开关。
例子如下:这里 (?i:b) 表示对字符 b 忽略大小写
- /a(?i:b)c/.match('aBc') #=> #<MatchData "aBc">
- /a(?i:b)c/.match('abc') #=> #<MatchData "abc">
使用 x 修饰符的例子:模板中的空白字符和 # 注释都会被忽略,因此可以写出较为优美的正则。
- # A contrived pattern to match a number with optional decimal places
- float_pat = /\A
- [[:digit:]]+ # 1 or more digits before the decimal point
- (\. # Decimal point
- [[:digit:]]+ # 1 or more digits after the decimal point
- )? # The decimal point and following digits are optional
- \Z/x
- float_pat.match('3.14') #=> #<MatchData "3.14" 1:".14">
注意:在 x 修饰符作用下,模板如果匹配空白字符,需要使用
\s
或者 \p{Space}
. 不使用 x 修饰符,添加注释使用
(?#
comment)
另:模式匹配使用的字符编码 encoding 同你的源文件一致,但也可通过以下修饰符修改:
- /pat/u - UTF-8
- /pat/e - EUC-JP
- /pat/s - Windows-31J
- /pat/n - ASCII-8BIT
正则表达式可以解析的字符串,两者编码或者一致,或者正则使用
US-ASCII 编码,字符串使用 ASCII 兼容的编码。
如果编码不同,会引发
异常。
可以使用
强行指定编码:
- r = Regexp.new("a".force_encoding("iso-8859-1"),Regexp::FIXEDENCODING)
- r =~"a\u3042"
- #=> Encoding::CompatibilityError: incompatible encoding regexp match
- (ISO-8859-1 regexp with UTF-8 string)
15、性能
一些变态的写法会导致性能极差:
- s = 'a' * 25 + 'd' 'a' * 4 + 'c'
- #=> "aaaaaaaaaaaaaaaaaaaaaaaaadadadadac"
- # 下面几句完成相同的匹配
- /(b|a)/ =~ s #=> 0
- /(b|a+)/ =~ s #=> 0
- /(b|a+)*\/ =~ s #=> 0
- # 很明显下面这句耗时更长
- /(b|a+)*c/ =~ s #=> 32
This happens because an atom in the regexp is quantified by both an immediate + and an enclosing * with nothing to differentiate which is in control of any particular character. The nondeterminism that results produces super-linear performance. (Consult Mastering Regular Expressions (3rd ed.), pp 222, by Jeffery Friedl, for an in-depth analysis). This particular case can be fixed by use of atomic grouping, which prevents the unnecessary backtracking:
- (start = Time.now) && /(b|a+)*c/ =~ s && (Time.now - start)
- #=> 24.702736882
- (start = Time.now) && /(?>b|a+)*c/ =~ s && (Time.now - start)
- #=> 0.000166571
另一个糟糕的例子,运行它足足花了60秒:
- # Match a string of 29 <i>a</i>s against a pattern of 29 optional
- # <i>a</i>s followed by 29 mandatory <i>a</i>s.
- Regexp.new('a?' * 29 + 'a' * 29) =~ 'a' * 29
The 29 optional as match the string, but this prevents the 29 mandatory as that follow from matching. Ruby must then backtrack repeatedly so as to satisfy as many of the optional matches as it can while still matching the mandatory 29. It is plain to us that none of the optional matches can succeed, but this fact unfortunately eludes Ruby.
One approach for improving performance is to anchor the match to the beginning of the string, thus significantly reducing the amount of backtracking needed.
- Regexp.new('\A' 'a?' * 29 + 'a' * 29).match('a' * 29)
- #=> #<MatchData "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa">
阅读(2799) | 评论(3) | 转发(0) |