新手问题 ruby 的正则里有个前视断言,那有木有后视断言涅?

ywencn · 2012年06月23日 · 最后由 zw963 回复于 2012年06月26日 · 5166 次阅读

前视断言

前视断言表示想要知道下一个指定的是什么,但并不匹配

肯定的前视断言 (?=) 假设我们想要匹配一个数的序列,该序列以一个圆点结束,但并不想把圆点作为模式匹配的一部分

teststr="123 456 789.012"
m=/\d+(?=\.)/.match(teststr)
puts m[0] #-> 789

如果反过来,是想查序列以一个原点开始,但并不想把圆点作为模式匹配的一部分,应该怎么搞?貌似在匹配网页的时候还是蛮常用的呀。 比如要找出 teststr="123 456 789.012"中的 012

用括号捕获就行了

[17] pry(main)> "123 456 789.012"[/(\d+)\.(\d+)/, 1]
=> "789"
[18] pry(main)> "123 456 789.012"[/(\d+)\.(\d+)/, 2]
=> "012"

你说的后视断言是这样吧;

[19] pry(main)> "123 456 789.012"[/(?<=\.)(\d+)/]
=> "012"

这个问题我见人问了很多次了。

不妨一次性全写出来,方便大家观看:

(?<=BEFORE) RE # => 前置条件,匹配 RE, 1.9 支持 RE (?=AFTER) # => 后置条件,匹配 RE, 1.8 支持 (?>INNER) # => 子查询,匹配 RE, 1.9 支持。

p.s. 我可记不住这些该死的括号还有方向,我是靠编辑器的 snippet 记忆的。前置条件我简写为:<<, 后置条件我写为 >>, 子查询我写为.. , 好记吧。

匿名 #5 2012年06月24日

puts "123 456 789.012"[/(?<=\.)(\d+)/, 1] Ruby 1.9.3 测试通过,Ruby 1.8.7 报 SyntaxError. 正如楼上所说,Ruby 1.8 不支持 Lookbehind, Ruby 1.9 支持。好在现在 1.9 是大势所趋,直接无视 1.8.

匿名 #6 2012年06月24日

#4 楼 @zw963 子查询能否举个例子?没见过那种 RE 的语法。

#6 楼 @tylerlong

子查询和其他两个理解起来差不多

例如:/RE1(?>RE)RE2/

首先会匹配 RE, 然后才会匹配 RE1 以及 RE2, 而且被 RE 匹配过的部分,RE1 和 RE2 就不会在匹配了。

典型的用途,当使用前置查询时,前置 RE 表达式必须是固定长度的 RE, 否则会出错。如果前置是一个无法确定数量的 pattern, 只能在前置条件中,嵌套一个子查询。

#7 楼 @zw963 好详细,看来 1.9 的知识还得再深入下,regexp 就有好多新亮点

匿名 #9 2012年06月26日

#7 楼 @zw963 你描述的概念学名叫做 Atomic Grouping, "An atomic group is a group that, when the regex engine exits from it, automatically throws away all backtracking positions remembered by any tokens inside the group. Atomic groups are non-capturing. The syntax is (?>group). " 我的理解是它主要用于在特定情况下提高正则解析性能 (通过抛弃 backtracking positions).

#9 楼 @tylerlong

没错,就是变相的终止了字符串的 backtracking, 准确地说,这都不算是一个断言。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号