在Perl 6中使用触发器操作符

ohm*_*udy 6 perl6 raku

我在doc.perl6.org中看到了触发器的使用,请参阅下面的代码:

my $excerpt = q:to/END/;
Here's some unimportant text.
=begin code
This code block is what we're after.
We'll use 'ff' to get it.
=end code
More unimportant text.
=begin code
I want this line.
and this line as well.
HaHa
=end code
More unimport text.
=begin code
Let's to go home.
=end code
END

my @codelines = gather for $excerpt.lines {
    take $_ if "=begin code" ff "=end code"
}

# this will print four lines, starting with "=begin code" and ending with
# "=end code"

.say for @codelines;
=begin code
This code block is what we're after.
We'll use 'ff' to get it.
=end code
=begin code
I want this line.
and this line as well.
HaHa
=end code
=begin code
Let's to go home.
=end code
Run Code Online (Sandbox Code Playgroud)

我想行之间保存=begin code和=end code成单独的阵列,像这样的:

['This code block is what we're after.', 'We'll use 'ff' to get it.']
['I want this line.', 'and this line as well.', 'HaHa']
['Let's to go home.']
Run Code Online (Sandbox Code Playgroud)

我知道语法可以做到这一点,但我想知道是否有一种更好的方式?

Bra*_*ert 9

您需要指定不要包含匹配的值.您可以通过添加^到要排除的运算符的一侧来执行此操作.在这种情况下,它是运营商的两面.

您还需要收集值以将其组合在一起.在这种情况下最简单的方法是在匹配之间放置它.
(如果您希望包含端点,则需要更多考虑才能使其正确)

my @codelines = gather {
  my @current;

  for $excerpt.lines {

    if "=begin code" ^ff^ "=end code" {

      # collect the values between matches
      push @current, $_;

    } else {
      # take the next value between matches

      # don't bother if there wasn't any values matched
      if @current {

        # you must do something so that you aren't
        # returning the same instance of the array
        take @current.List;
        @current = ();
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

如果你需要结果是一个数组数组(可变).

if @current {
  take @current;
  @current := []; # bind it to a new array
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用do for共享相同迭代器的序列.
这是有效的,因为for它比实际上更加渴望map.

my $iterator = $excerpt.lines.iterator;

my @codelines = do for Seq.new($iterator) {
    when "=begin code" {
        do for Seq.new($iterator) {
            last when "=end code";
            $_<> # make sure it is decontainerized
        }
    }
    # add this because `when` will return False if it doesn't match
    default { Empty }
}
Run Code Online (Sandbox Code Playgroud)

map取一个序列并将其转换为另一个序列,但在尝试从序列中获取下一个值之前不会执行任何操作.
for立即开始迭代,只在你告诉它时停止.

因此map即使在单个线程上运行也会导致竞争条件,但for不会.