如何使用正则表达式在Perl中限制匹配结果?

7

在进行了大量研究后,我来寻求您的帮助:

我正在尝试限制Perl正则表达式在大文本中执行的替换次数。我在谷歌上搜索并发现其格式为{2,3}(最小值,最大值),然而这似乎是针对不同于我使用的语法的形式。

$replaced=~s/$var/$var2/g; # replaces all ocurrences
$replaced=~s/$var/$var2/;  # replaces only first one

我的非最优解决方案:

for($i=0; $i<8; $i++){

    $replaced=~s/$var/$var2/;
}

我尝试过的方法:

$replaced=~s/$var/$var2/{8};
$replaced=~s/$var/$var2{8}/;

任何帮助都将不胜感激!

编辑: 好的,基本上需要涉及循环,是不是很奇怪没有内置参数来限制它?


1
你为什么认为你的解决方案不够优化? - Vlad
2
如果我正在解析一个100MB的文件,并且出现在块的后半部分,那么每次都需要读取前50MB,如果可以限制这个范围,那么只需要一次读取。 - isJustMe
1
这只是一个例子,数据集是随机生成的,出现位置可能在文件的任何地方。 - isJustMe
3
@James_R_Ferguson - 为什么这很像 Perl? - Leonardo Herrera
2
一个更加 Perl 风格的循环是 for (1..8) - Ven'Tatsu
显示剩余6条评论
3个回答

7

使用\G的答案可能是实现您想要的功能的最实用方法,但只是为了好玩、增长见识或其他原因,这里提供另一种方法(需要perl 5.10或更高版本),使用代码断言和回溯控制动词(*COMMIT)(*FAIL)

my $str = "Bananas in pajamas are coming down the stairs";
my $limit = 3;
my $count;

$str =~ s/(*COMMIT)(?(?{ $count++ >= 3 })(*FAIL))a/A/g;
say $str;

这会将文本“BAnAnAs in Pajamas are coming down the stairs”放在$str中 - 只有前三个“a”受到影响,并且在第三个后停止扫描字符串以查找更多匹配项。


1
s/(a)/$count++ < 3 ? "A" : $1/ge - tchrist
@tchrist 啊,我明白了。是的,那样做可行,但不会停止匹配,如果你有大量数据和/或你的模式很昂贵,这可能很重要。 - hobbs
@tchrist,我是那个关于大小写折叠模块 khw 向您发送电子邮件的人。我已经通过电子邮件直接跟进了您。 - hobbs
我有一个有趣的邮件设置。这意味着你可能在一些不容易被注意到的地方。我会四处寻找。 - tchrist
@hobbs 这个解决方案会在每次迭代中解析整个字符串吗?还是会从上一次匹配结束的地方继续进行? - isJustMe
显示剩余7条评论

4

我不太擅长Perl,但我相信你想使用"\G断言"(更多信息在这里),它将继续在前一次匹配结束的地方搜索新的匹配:

for($i=0; $i<8; $i++){

    $replaced=~s/\G$var/$var2/;
}

我不确定它是否确实更有效率,但它似乎是为此而设计的...


1
$i变量在这里没有任何作用。更优雅的写法是s/\G$var/$var2/ for 1 .. 8; - Zaid
@Zaid:但在这种情况下,您不能省略$replaced=~,因为for 1..8会设置$_ - choroba
正确,应该以 $replaced =~ 开始。 - Zaid

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接