在此示例脚本中:
#perl 5.26.1
$foo = "batcathat";
if ($foo =~ /cat/g) {
print "yes\n";
} else {
print "no\n";
}
if ($foo =~ /cat/g) {
print "yes\n";
} else {
print "no\n";
}
字符串
这将打印:
yes
no
型
预期输出为:
yes
yes
型
我可以通过打印字符串来确认它没有通过运行正则表达式匹配而发生变化。
为什么Perl似乎只对正则表达式求值一次?我在Google或手册上找不到关于这方面的信息,而且这种行为对我来说并不直观。我希望每次你对正则表达式匹配求值时,它都是从fresh开始的,并且不记得任何关于前一个匹配的信息。
编辑:对于未来的上下文,这个问题是在我发现一段代码后提出的,看起来像这样:
while ( $foo =~ /pattern/g) { $some_incrementing_var++ };
型
我最初并不理解这个while循环是如何终止的,因为乍一看,它看起来像一个无限循环。
3条答案
按热度按时间vu8f3i0k1#
标量上下文中的
//g
开始匹配上一个/g匹配结束的位置。由于cat
只出现一次,因此它返回false以指示第二次没有匹配。这在循环中很有用:
字符串
我们可以用
pos
来看看发生了什么。的数据
但是,虽然这在循环中很有用,但它对
if ( //g )
没有意义(除非你正在展开一个循环)。这意味着什么?“检查它是否匹配,并毫无理由地继续检查更多的匹配”?显然,这没有意义。删除g
以打印yes
两次。i7uq4tfw2#
如果省略
//g
(“global”)修饰符,将得到预期的输出:字符串
我认为没有必要在代码中使用
//g
。jutyujz03#
标量上下文中的
/g
是我最喜欢的工具之一,它在perlop中的文档非常长。对于它的文档来说,这似乎是一个奇怪的地方,但是有一些标志会影响匹配操作符的工作方式,还有一些标志会影响模式的工作方式(参见Know the difference between regex and match operator flags)。@ikegami提到了
pos
,你可以在perlfunc中读到它。Perl跟踪它在a字符串中的位置。在标量上下文中没有/g
,匹配操作符从字符串的开头开始,向结尾移动。匹配完成后,它就完成了。下一个匹配再次从字符串的开头开始。\g
稍微改变了这一点。第一个匹配从字符串的开头开始,匹配(如果可以的话),并设置匹配结束的位置后一个位置。这就是pos
。下一次使用\g
,匹配从pos
开始。在您的情况下,在列表上下文中,它也在做同样的事情,但会用尽。它进行第一个匹配,然后从该位置开始尝试下一个匹配。这就是为什么列表上下文中的匹配无法找到重叠匹配:它在重叠开始的地方开始匹配。Jeffrey Friedl的Mastering Regular Expressions,尽管已经很老了,是一个很好的关于正则表达式如何工作的调查,它们可以以不同的方式工作,以及各种方式如何排除其他方式可能具有的特征。
字符串
这将产生:
型
这个位置是按字符串跟踪的,并且在
\g
匹配失败后重置(就像其他regex副作用变量一样):型
输出显示两次查找
cat
的尝试都成功了,因为dog
尝试失败并重置了pos
:型
但是,也有一种方法可以解决这个问题。
/c
标志告诉match操作符在失败时不要重置pos
:型
现在,您可以返回到原始输出:
型
这允许你做类似这个非常简单的例子的事情。你可以匹配某个特定的东西,如果这不起作用,尝试其他东西,而不会丢失你在字符串中的位置:
型
这允许你在非常复杂的情况下遍历字符串,并在匹配过程中做一些事情,我想我在Mastering Perl中有一些例子。