简体   繁体   English

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

[英]Save result from flip-flop in variable?

I have about 1kB of text from STDIN 我有大约1kB来自STDIN的文字

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

and I would like to get the content between open1 and close1 , so /open1/../close1/ comes to mind. open1close1之间的内容,所以/open1/../close1/

I have only seen it been used in one liners and in scripts in while-loops and $_ . 我只看到它在while循环和$_中的一个衬里和脚本中使用。

Question

How can I get the result from /open1/../close1/ in my script when everything is in $f ? 当所有内容都在$f时,如何从我的脚本中获取/open1/../close1/的结果?

Capturing all matches with a single regular expression 使用单个正则表达式捕获所有匹配项

If you want to capture all the lines between open1 and start1 markers (excluding the markers) , it is easily done with a single regular expression: 如果你想捕获所有的线open1start1标记(不包括标记),很容易用一个正则表达式来完成:

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

my @matches = ( $f =~ m/\bopen1\b(.*?)\bclose1\b/gs );

for my $m (@matches) {
  print "$m";
}

where 哪里

  • s modifier treats the string as a single line; s modifier将字符串视为单行;
  • g modifier captures all the matches; g modifier捕获所有匹配项;
  • (.*?) matches a group of any characters using the lazy quantifier (.*?)使用延迟量词匹配一组任何字符

Using the range operator 使用范围运算符

The range operator (so-called flip-flop) is not very convenient for this task if you want to avoid capturing the markers, because an expression like /open1/ .. /close1/ returns true for the lines matching the patterns. 如果你想避免捕获标记,范围操作符(所谓的触发器)对于这个任务来说不是很方便,因为像/open1/ .. /close1/这样的表达式对于匹配模式的行返回true

The expression /^open1$/ .. /^close1$/ returns false until /^open1$/ is true . 表达式/^open1$/ .. /^close1$/返回false,直到/^open1$/true The left regular expression stops being evaluated once it matches the line, and keeps returning true until /^close1$/ becomes true . 一旦它匹配的线,并保持返回true,直到左正则表达式停止正在评估/^close1$/变为 When the right expression matches, the cycle is restarted. 当右表达式匹配时,重新启动循环。 Thus, the open1 and close1 markers are included into $matches . 因此, open1close1标记包含在$matches

It is even less convenient, if the input is stored in a variable, because you will need to read the contents of the variable line by line, eg: 如果输入存储在变量中,则更不方便,因为您需要逐行读取变量的内容,例如:

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

Note, it is possible to use arbitrary Perl expressions as operands of the range operator. 注意,可以使用任意Perl表达式作为范围运算符的操作数。 I wouldn't recommend this code, as it is not very efficient, and not very readable. 我不推荐这段代码,因为它不是很有效,而且不太可读。 At the same time it is easy to adapt the first example to the case where the open1 and close1 markers are included into the set of matches, eg: 同时,很容易使第一个示例适应open1close1标记包含在匹配集中的情况,例如:

my @matches = ( $f =~ m/\bopen1\b(.*?)\bclose1\b/gs );
for my $m (@matches) {
  print "open1${m}close1\n";
}

You can rewrite how $f is generated so that it takes advantage of the flip-flop inside a while loop: 你可以重写$f的生成方式,以便它利用while循环中的触发器:

my ( $f, $matched );
while ( <> ) {
    $f .= $_;
    $matched .= $_ if /open1/ .. /close1/;
}

You can also employ split . 您也可以使用拆分 To get what is between the first pair of open1 and close1 获取第一对open1close1之间的close1

my $open_to_close = (split /open1|close1/, $f)[1];

The delimiter can be either open1 or close1 , so returned is a list of three elements: before open1 , between them, and after close1 . 分隔符可以是open1close1 ,因此返回的是三个元素的列表: open1之前,它们之间和close1之后。 We take the second element. 我们采取第二个要素。


If there are more open1 / close1 pairs take all odd-indexed elements. 如果有更多open1 / close1对,则采用所有奇数索引元素。

Either get the array as well 也可以获得阵列

my @parts = split /open1|close1/, $f;

my @all_open_to_close = @parts[ grep { $_ & 1 } 0..$#parts ];

or get it directly from the list 或直接从列表中获取

my @all_open_to_close = 
    grep { CORE::state $i; ++$i % 2 == 0 }  split /open1|close1/, $f;

The state is a feature from v5.10 . v5.10一个功能 If you already use that you don't need CORE:: prefix. 如果您已经use它,则不需要CORE::前缀。

Another way is to create a new inputs stream out of the contents of $f . 另一种方法是从$f的内容中创建一个新的输入流。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM