我有大约1kB来自STDIN的文字
my $f = join("", <STDIN>);
我想在open1
和close1
之间获取内容,因此会想到/open1/../close1/
。
我只看到它在while循环和$_
中的一个衬里和脚本中使用过。
问题
当所有内容都在/open1/../close1/
时,如何从我的脚本中获取$f
的结果?
答案 0 :(得分:4)
如果您想捕获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 。左正则表达式在与行匹配后停止计算,并继续返回 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";
}
答案 1 :(得分:2)
你可以重写console.log(suggestionData.query.pages[pageid].extract");
的生成方式,以便它利用$f
循环中的触发器:
while
答案 2 :(得分:1)
您也可以使用split。获取第一对open1
和close1
my $open_to_close = (split /open1|close1/, $f)[1];
分隔符可以是open1
或close1
,因此返回的是三个元素的列表:open1
之前,它们之间和close1
之后。我们采取第二个要素。
如果有更多open1
/ close1
对,则采用所有奇数索引元素。
也可以获得数组
my @parts = split /open1|close1/, $f;
my @all_open_to_close = @parts[ grep { $_ & 1 } 0..$#parts ];
或直接从列表中获取
my @all_open_to_close =
grep { CORE::state $i; ++$i % 2 == 0 } split /open1|close1/, $f;
答案 3 :(得分:1)
另一种方法是从$f
的内容中创建一个新的输入流。
open my $fh, '<', \$f;
while (<$fh>) {
if (/open1/ .. /close1/) {
...
}
}