Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 使用触发器操作符跟踪基于缩进的状态_Perl - Fatal编程技术网

Perl 使用触发器操作符跟踪基于缩进的状态

Perl 使用触发器操作符跟踪基于缩进的状态,perl,Perl,我试图熟悉触发器操作符,这样在进行有状态循环时,我可以将其作为额外的抽象在头脑中,即使教科书式的状态机在这种情况下工作得非常好(而且冗长且变量丰富)。我想跟踪缩进,似乎我仍然需要在每个if块的开头手动调整缩进,在这种情况下我称之为缩进触发器,对吗? 以下是我的想法: 节目: use v5.20; use strict; use warnings; my $shiftwidth = 3; # block_rx: start of indented block marker, without l

我试图熟悉触发器操作符,这样在进行有状态循环时,我可以将其作为额外的抽象在头脑中,即使教科书式的状态机在这种情况下工作得非常好(而且冗长且变量丰富)。我想跟踪缩进,似乎我仍然需要在每个if块的开头手动调整缩进,在这种情况下我称之为缩进触发器,对吗? 以下是我的想法:

节目

use v5.20;
use strict;
use warnings;

my $shiftwidth = 3;

# block_rx: start of indented block marker, without leading spaces
# Keeps state of indentation, which is increased on encountering block marker
# and decreased on matching outdent.
# Function should always get indentation level from context it was called in.
# Returns: true if in indented block, ^ff^, else false

sub indenting_flipflop {
    my $block_rx = $_[0];
    $_ = $_[1];
    my $level = $_[2];
    my $indent = indent($level);
    my $inner_indent = indent($level + 1);
    return ((/^$indent$block_rx/) ... (!/^$inner_indent/)) =~ s/.*E//r;
}

sub indent {
    return ' ' x ($shiftwidth * $_[0]);
}

while (<DATA>) {
    my $level = 0;
    if (indenting_flipflop('books', $_, $level)) {
        $level++;
        if (indenting_flipflop('book', $_, $level)) {
            $level++;
            if (/author: (.*)/) {
              say $1;
            }
        }
    }
}

__DATA__
books:
   book:
      author: Mark Twain
      price: 10.99
   game:
      author: Klaus Teuber
      price: 15.99
   book:
      author: Jane Austen
      price: 12.00

books:
   book:
      author: Mark Twain
      price: 10.99
   game:
      author: Klaus Teuber
      price: 15.99
   book:
      author: Jane Austen
      price: 12.00
Mark Twain
Jane Austen
Mark Twain
Jane Austen
Mark Twain
Klaus Teuber
Jane Austen
Mark Twain
Klaus Teuber
Jane Austen
实际产出

use v5.20;
use strict;
use warnings;

my $shiftwidth = 3;

# block_rx: start of indented block marker, without leading spaces
# Keeps state of indentation, which is increased on encountering block marker
# and decreased on matching outdent.
# Function should always get indentation level from context it was called in.
# Returns: true if in indented block, ^ff^, else false

sub indenting_flipflop {
    my $block_rx = $_[0];
    $_ = $_[1];
    my $level = $_[2];
    my $indent = indent($level);
    my $inner_indent = indent($level + 1);
    return ((/^$indent$block_rx/) ... (!/^$inner_indent/)) =~ s/.*E//r;
}

sub indent {
    return ' ' x ($shiftwidth * $_[0]);
}

while (<DATA>) {
    my $level = 0;
    if (indenting_flipflop('books', $_, $level)) {
        $level++;
        if (indenting_flipflop('book', $_, $level)) {
            $level++;
            if (/author: (.*)/) {
              say $1;
            }
        }
    }
}

__DATA__
books:
   book:
      author: Mark Twain
      price: 10.99
   game:
      author: Klaus Teuber
      price: 15.99
   book:
      author: Jane Austen
      price: 12.00

books:
   book:
      author: Mark Twain
      price: 10.99
   game:
      author: Klaus Teuber
      price: 15.99
   book:
      author: Jane Austen
      price: 12.00
Mark Twain
Jane Austen
Mark Twain
Jane Austen
Mark Twain
Klaus Teuber
Jane Austen
Mark Twain
Klaus Teuber
Jane Austen

如果我不必在循环中手动调整
$level
,那也很好。

带有动态操作数的触发器运算符使用起来很棘手,可能无法达到预期效果。Perl为代码中出现的每个触发器运算符维护一个“状态”,而不是为作为操作数提供给触发器运算符的每个表达式维护一个单独的状态

考虑以下代码:

sub foo { m[<foo>] .. m[</foo>] }
sub bar { m[<bar>] .. m[</bar>] }

while (<DATA>) {    
    print "FOO:$_" if foo();
    print "BAR:$_" if bar();
}    
__DATA__
<foo>
   <bar>
      123
   </bar>
   <baz>
       456
   </baz>
</foo>
sub ff { my $tag = shift; m[<$tag>] .. m[</$tag>] }
while (<DATA>) {
    print "FOO:$_" if ff("foo");
    print "BAR:$_" if ff("bar");
}
__DATA__
<foo>
   <bar>
      123
   </bar>
   <baz>
       456
   </baz>
</foo>
但这一条(用每一行输入定义新函数)并不:

sub fff { my $tag = shift; sub { m[<$tag>] .. m[</$tag>] } }
while (<DATA>) {
    print "FOO:$_" if fff("foo")->();
    print "BAR:$_" if fff("bar")->();
}
__DATA__
...


(不确定
s/*E//r
是做什么用的)

使用严格和警告?是否将级别初始化为0?锚定触发器左操作数正则表达式?@ysth:对不起,我现在解决了这些问题,并使我的问题更清楚。当满足触发器条件时,触发器的字符串返回值以“E0”结尾;请看(但我不确定这对OP的解决方案有何影响)注意,仅仅一个新的匿名函数是不够的;它必须是一个闭包(参考至少一个外部词法)才能获得它自己的触发器状态数据(至少这是我的记忆),谢谢你的回答!我仍在阅读,首先让我说我使用了
s/*E//r
,因为我认为这是使结束值返回false(“0”)从而排除它的最简单方法,因为我希望while循环中的内部条件仅在行仍然缩进时匹配。这很有效,非常酷!在最后一段代码中,它仍然必须是三个点,因此
sub{/^$expr1/..!/^$expr2/}
,然后它直接工作。好的,我将切换回
..
my %FF;
sub fff { my $tag = shift; $FF{$tag} //= sub { m[<$tag>] .. m[</$tag>] } }
while (<DATA>) {
    print "FOO:$_" if fff("foo")->();
    print "BAR:$_" if fff("bar")->();
}
__DATA__
...
...
return ((/^$indent$block_rx/) ... (!/^$inner_indent/)) =~ s/.*E//r;
my %FF;
sub flipflopfunc {
    my ($expr1,$expr2) = @_;
    return $FF{$expr1}{$expr2} //= 
        sub { /^$expr1/ ... !/^$expr2/ };
}
...
return flipflopfunc("$indent$block_rx",$inner_indent)->() =~ s/.*E//r;