加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

正则表达式中的look-around

发布时间:2020-12-14 02:07:06 所属栏目:百科 来源:网络整理
导读:使用向前看和上后看你可以来完成各种各样的assert来满足你的需求。 在字符串处理时,你可以向前或者向后看,同时你可以让你所看的pattern是成功或者失败。 就像Java中的assert() (?=pattern) is a positive look-ahead assertion assert(pattern match) -- (?
使用向前看和上后看你可以来完成各种各样的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/(?<=,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 "$1n" while /(?=(.*))/g;

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读