将触发器的结果保存在变量中?

时间:2017-01-02 14:04:02

标签: regex perl

我有大约1kB来自STDIN的文字

my $f = join("", <STDIN>);

我想在open1close1之间获取内容,因此会想到/open1/../close1/

我只看到它在while循环和$_中的一个衬里和脚本中使用过。

问题

当所有内容都在/open1/../close1/时,如何从我的脚本中获取$f的结果?

4 个答案:

答案 0 :(得分:4)

使用单个正则表达式捕获所有匹配项

如果您想捕获open1start1标记(不包括标记)之间的所有行,可以使用单个正则表达式轻松完成:

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 。当右表达式匹配时,重新启动循环。因此,open1close1标记包含在$matches中。

如果输入存储在变量中,则更不方便,因为您需要逐行读取变量的内容,例如:

my $matches = "";
my @lines = split /\n/, $f;
foreach my $line (@lines) {
  if ($line =~ m/^open1$/ .. $line =~ m/^close1$/) {
    $matches .= "$line\n";
  }
}

注意,可以使用任意Perl表达式作为范围运算符的操作数。我不推荐这段代码,因为它不是很有效,而且不太可读。同时,第一个示例很容易适应open1close1标记包含在匹配集中的情况,例如:

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。获取第一对open1close1

之间的内容
my $open_to_close = (split /open1|close1/, $f)[1];

分隔符可以是open1close1,因此返回的是三个元素的列表: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;

statefeature 来自v5.10。如果您已经use表示不需要CORE::前缀。

答案 3 :(得分:1)

另一种方法是从$f的内容中创建一个新的输入流。

open my $fh, '<', \$f;
while (<$fh>) {
    if (/open1/ .. /close1/) {
        ...
    }
}