正则表达式中的look-around

使用向前看和上后看你可以来完成各种各样的assert来满足你的需求。
在字符串处理时,你可以向前或者向后看,同时你可以让你所看的pattern是成功或者失败。
就像Java中的assert()

(?=pattern)
    is a positive look-ahead assertion
assert(pattern match) -->

(?!pattern)
    is a negative look-ahead assertion
assert(pattern not match) -->

(?<=pattern)
    is a positive look-behind assertion
assert(pattern match) <--

(?<!pattern)
    is a negative look-behind assertion
assert(pattern not match) <--

look-ahead -->向前看
look-behind <--向后看

1. 寻找最后出现的字符串
这里有很多不使用左右看的方法来完成寻找最后出现的字符串,
但是如果你需要的是:最后的字符串是foo并且foo之后再也没有foo字符串了(可以有其它的字符串),你可以使用:

/foo(?!.*foo)/

正则表达式引擎会在找到foo之后使用look-around中的pattern .*foo去匹配,如果匹配到,但是因为是getative的,
所有assert失败,然后正则表达式引擎会继续查找下一个foo。

例如:foobar会匹配到第一个foo

而foobarfooeee会匹配到第二个foo

以(?<=foo)作为分隔符


2. 替换之前,之后或者中间的字符
Many substitutions match a chunk of text and then replace part or all of it.
You can often avoid that by using look-arounds.
For example, if you want to put a comma after every foo:
很多替换方法匹配一串字符的全部或者一部分。你可以使用look-around来实现。
例如,你想要在每个foo之后都加一个逗号:

s/(?<=foo)/,/g; # 不使用向后看: s/foo/foo,/g or s/(foo)/$1,/g

或者给lookahead中间加一个-

s/(?<=look)(?=ahead)/-/g;

需要注意的是,左右看这种方法不能有变量长度,这意味着你不能在它之后或者之内使用像(?, *, +, or {1,5}) 这样的限定符。

将lookahead替换成look-ahead



3. 匹配一个pattern但是不包含其它的pattern
You might want to capture everything between foo and bar that doesn't include baz.
The technique is to have the regex engine look-ahead at every character to ensure
that it isn't the beginning of the undesired pattern:
你可能想匹配所有在foo和bar之间的字符串,但是foo之后不能是baz。
你可以使用下面的表达式:

/foo # Match starting at foo
(                   # Capture
    (?:             # Complex expression(you do not use the backreference):
        (?!baz)   # make sure we're not at the beginning of baz
                     #or using (?!.*baz) make sure the whole string between foo and bar not contains baz
        .            # accept any character
    )*              # any number of times
    )               # End capture
    bar             # and ending at bar
/x;

foo((?:(?!baz).*))bar

不会匹配foobazddbar

foo之后不知baz,所以匹配上了

如果想匹配foo和bar之间没有baz可以使用:

foo((?:(?!.*baz).*))bar



4. 嵌套
look-arounds是可以嵌套的。look-arounds的自表达式会冲它上层继承开始位置,然后在这个开始位置的基础上
左右看同时不影响上层的位置,子表达式和父亲是相互独立的,它们独自维护自己的位置信息。

这个概念很简单,但是表达式很快就会变的很难懂。所有推荐对正则表达式加注释。
下面让我们来看一个正则表达式的例子。我们希望在任何分隔符(为了简单我们只用,)之后加一个空格,
但是在两个数字之间的,不加空格。

s/(?<=,        # after a comma,
    (?!        # but not matching
      (?<=\d,) #   digit-comma before, AND
      (?=\d)   #   digit afterward
    )
  )/ /gx;      # substitute a space

(?<=,(?!(?<=\d,)(?=\d)))

在,之后加空格,但是数字之间的不加


注意,我们可以使用多个lookaround来完成不同的条件。就像And或这Or。
事实上你可是使用布尔代数表达式 ( NOT (a AND b) === (NOT a OR NOT b) )
来转化上面的表达式

s/(?<=,        # after a comma, but either
    (?:
      (?<!\d,) #   not matching digit-comma before
      |        #   OR
      (?!\d)   #   not matching digit afterward
    )
  )/ /gx;      # substitute a space


(?<=,(?:(?<!\d,)|(?!\d)))

4. 捕获
有时我们会在look-around中捕获大括号。你可能认为你不会用到。
但是还是请你记住: the capturing parentheses must be within the look-around expression。
从enclosing expression来看,lookaround其实没有进行匹配。

最有用的技巧是在全局匹配模式时寻找重叠的匹配。
你可以捕获子串但是不需要消耗它,然后它可以对后面的匹配有效。
或许最简单的例子就是获得所有的右边的子串

print "$1\n" while /(?=(.*))/g;

注意这个模式理论上不会消耗任何一个字符,但是Perl在空匹配时会自动追加一个字符来防止无限循环。
http://www.perlmonks.org/?node_id=518444

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值