4

我很困惑这些环视断言在 perl 中有什么用?

例如这个:

(?=pattern)

或积极的前瞻性。所以这是我的问题:

  1. 这些有什么用?他们使用什么样的实例?
  2. 与问题 1 相关,我为什么要提前看正则表达式模式?这不是更多的工作吗?向前看,然后再次执行模式匹配。

如果可能的话,我需要一个非常清楚的例子。谢谢

4

5 回答 5

4

要将逗号之间的内容大写,您可以使用:

(my $x = 'a,b,c,d,e') =~ s/(?<=,)([^,]*)(?=,)/ uc($1) /eg;   # a,B,C,D,e

                  a,b,c,d,e
Pass 1 matches      -
Pass 2 matches        -
Pass 3 matches          -

如果你不使用环视,这就是你会得到的,

(my $x = 'a,b,c,d,e') =~ s/,([^,]*),/ ','.uc($1).',' /eg;   # a,B,c,D,e

                  a,b,c,d,e
Pass 1 matches     ---
Pass 2 matches         ---

前瞻不仅可以避免重复,而且没有它就无法工作!


另一个比较常见的用法是作为字符串的一部分,相当于[^CHAR].

foo(?:(?!foo|bar).)*bar  # foo..bar, with no nested foo or bar

您可以使用它来缩小字符类别。

\w(?<!\d)     # A word char that's not a digit.

尽管现在可以使用(?[ ... ]).


它在更深奥的模式中也很有用。

 /a/ && /b/ && /c/

可以写成

 /^(?=.*?a)(?=.*?b).*?c/s
于 2013-06-06T06:41:21.517 回答
3

lookahead让您在不实际匹配的情况下检查模式。

当你这样做时a(?=b),你会匹配a如果它后面跟着b. 注意:它不匹配b


所以,

1>您可以从使用中提取hello(不带##hello#

(?<=#)hello(?=#)

2>您可以验证具有要求的密码,例如密码必须有2位数字,2个字母或更多的任何其他字符

^(?=(.*\d){2})(?=(.*[a-z]){2}).*$

尝试在没有前瞻的情况下进行上述操作,您会意识到它的重要性

于 2013-06-06T06:46:13.143 回答
1

我发现前瞻对于检查多个条件特别有用。例如,考虑一个正则表达式,它检查密码是否至少包含一个小写字母、一个大写字母、一个数字和一个符号字符,并且长度至少为 8 个字符:

^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).{8,}$

尝试设计一个正则表达式来做同样的事情而不用前瞻断言!这是可能的,但它非常麻烦。

同时,我发现后视对于检查边界条件特别有用——例如,匹配一个 0 的字符串,除非它前面有另一个数字,比如1000067.

这些是我的经验,但当然还有更多实际用途,每个人使用工具的方式因人而异。

于 2013-06-06T06:46:40.893 回答
0

使用环视的原因有很多,例如

  1. 限制被认为匹配的子字符串:s/(?<=[0-9])+(?=[0-9])/-/而不是s/([0-9])+([0-9])/$1-$2/.
  2. and-ing 各种条件一起使用:/(?=\p{Uppercase}\p{Lowercase})\p{InBasicLatin}{2,}/.
于 2013-06-06T06:50:17.700 回答
0

当您需要一个模式来帮助定位匹配但您不希望该模式成为捕获内容的一部分时,环视断言很有用。

这是一个带有前瞻断言的简单场景:

假设我有

my $text = '98 degrees, 99 Red Balloons, 101 Dalmatians'

我想将红色气球的数量从以前的值更改为9001,所以我使用

$text =~ s/\d+(?=Red Balloons)/9001/;
于 2013-06-06T07:23:11.770 回答