【发布时间】:2018-05-12 13:00:00
【问题描述】:
如何只匹配字符串中某个单词的一个实例? 例如,以“fred”作为我的测试词,字符串“fredwilmawilliamjohn”的匹配应该为 TRUE,但“fredwilmawilliamfred”的匹配应该为 FALSE?
【问题讨论】:
-
如果你在做Learning Perl中的练习,你应该自己做。
如何只匹配字符串中某个单词的一个实例? 例如,以“fred”作为我的测试词,字符串“fredwilmawilliamjohn”的匹配应该为 TRUE,但“fredwilmawilliamfred”的匹配应该为 FALSE?
【问题讨论】:
您可以通过在列表上下文中使用/g 标志来计算匹配数,并将其转换为标量上下文。
use strict;
use warnings;
use feature 'say';
for my $string (qw(fredwilmawilliamjohn fredwilmawilliamfred) ) {
my $count = () = $string =~ m/(fred)/g;
if ( $count == 1 ) {
say $string;
}
}
最相关的部分是= () =,它强制匹配到列表上下文。然后my $count 会将该匹配列表强制转换为标量上下文,从而为您提供列表中的项目数。这是你的匹配数。
【讨论】:
= () = 也被称为 'goatse operator' :)
/fred(*COMMIT)(?!.*?fred)/s
(*COMMIT)(在 perl 5.10 中添加)表示在匹配 fred 之后,如果正则表达式的其余部分失败,请不要回溯并再次尝试匹配它。正则表达式的其余部分表示如果.*?fred(任意数量的任何字符后跟fred)在第一个fred之后匹配,则不匹配,即没有进一步的fred。
在 5.10 之前,您需要强制正则表达式中的第一个 fred 只匹配字符串中的第一个 fred,如下所示:
/^(?:(?!fred).)*+fred(?!.*?fred)/s
(匹配任意数量的字符,只要它们不是 fred 的开头,然后再匹配不能被另一个 fred 跟随的 fred)。
或者
/^(?>.*?fred)(?!.*?fred)/s
(从字符串的开头开始,不允许回溯,找到第一个fred,并断言后面没有fred)
(在整个过程中,/s 用于使. 匹配任何字符,而不仅仅是任何非换行符。)
【讨论】:
听起来您想匹配该模式并验证它随后不会出现在字符串中。这个怎么样,使用负前瞻
m/fred(?!.*fred)/
分解:
?! -- 后面没有
.* -- 零个或多个字符
【讨论】:
!m/fred(?=.*fred)/ 可以在这里工作。