我有来自 STDIN 的大约 1kB 的文本
my $f = join("", <STDIN>);
我想获取open1
和close1
之间的内容,所以想到了/open1/../close1/
。
我只看到它被用在一个线程和 while 循环和 $_
的脚本中。
问题
当所有内容都在 $f
中时,如何在我的脚本中从 /open1/../close1/
获取结果?
最佳答案
用一个正则表达式捕获所有匹配项
如果你想捕获 open1
和 start1
标记 (不包括标记) 之间的所有行,只需一个正则表达式:
my $f = join("", <STDIN>);
my @matches = ( $f =~ m/\bopen1\b(.*?)\bclose1\b/gs );
for my $m (@matches) {
print "$m";
}
在哪里
s
修饰符将字符串视为单行;g
修饰符捕获所有匹配;(.*?)
使用 lazy quantifier 匹配一组任意字符
使用范围运算符
如果您想避免捕获标记,范围运算符(所谓的触发器)对于此任务不是很方便,因为像 /open1/../close1/
这样的表达式会返回true 匹配模式的行。
表达式 /^open1$/../^close1$/
返回 false 直到 /^open1$/
为 真的。左边的正则表达式一旦与该行匹配就停止求值,并一直返回 true 直到 /^close1$/
变为 true。当正确的表达式匹配时,循环重新开始。因此,open1
和 close1
标记包含在 $matches
中。
如果输入保存在变量中就更不方便了,因为你需要逐行读取变量的内容,例如:
my $matches = "";
my @lines = split /\n/, $f;
foreach my $line (@lines) {
if ($line =~ m/^open1$/ .. $line =~ m/^close1$/) {
$matches .= "$line\n";
}
}
请注意,可以使用任意 Perl 表达式作为范围运算符的操作数。我不推荐这段代码,因为它效率不高,而且可读性不强。同时,第一个示例很容易适应 open1
和 close1
标记包含在匹配集中的情况,例如:
my @matches = ( $f =~ m/\bopen1\b(.*?)\bclose1\b/gs );
for my $m (@matches) {
print "open1${m}close1\n";
}
关于regex - 将触发器的结果保存在变量中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41428316/