Операторы триггера с динамическими операндами сложны в использовании и могут не выполнять то, что вы ожидаете.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>
Вывод:
FOO:<foo>
FOO: <bar>
BAR: <bar>
FOO: 123
BAR: 123
FOO: </bar>
BAR: </bar>
FOO: <baz>
FOO: 456
FOO: </baz>
FOO:</foo>
Пока все хорошо, верно?Этот подход не будет хорошо масштабироваться, когда вместо двух отслеживаются 100 различных тегов, поэтому давайте попробуем этот код:
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>
Теперь получим
FOO:<foo>
BAR:<foo>
FOO: <bar>
BAR: <bar>
FOO: 123
BAR: 123
FOO: </bar>
BAR: </bar>
Что случилось?BAR
всегда печатается с теми же строками, что и FOO
, а последней строкой вывода является строка </bar>
, хотя в тегах <foo></foo>
все еще заключено больше данных.
Что произошлоявляется то, что код содержит один оператор триггера, определенный в подпрограмме ff
, и этот оператор поддерживает одно состояние.Состояние изменяется на «true», когда ff("foo")
вызывается с первой строкой ввода, и оно остается «true», пока не встретит ввод и операнд, который удовлетворяет второму выражению в операторе триггера, что происходит с 4-мстрока, когда вызывается ff("bar")
.Он не поддерживает отдельное состояние для тегов foo
и bar
, как это было в первом примере.
Передача другого ввода в функцию indenting_flipflop
и ожидание, что оператор триггера в этой функции просто будет работатьввод такого типа не будет работать.
Обновление : поэтому этот подход, определяющий одну новую функцию для каждого тега, работает:
sub fff { my $tag = shift; sub { m[<$tag>] .. m[</$tag>] } }
my $foo = fff("foo");
my $bar = fff("bar");
while (<DATA>) {
print "FOO:$_" if $foo->();
print "BAR:$_" if $bar->();
}
__DATA__
...
но эта (определение новых функций с каждой строкой ввода) не:
sub fff { my $tag = shift; sub { m[<$tag>] .. m[</$tag>] } }
while (<DATA>) {
print "FOO:$_" if fff("foo")->();
print "BAR:$_" if fff("bar")->();
}
__DATA__
...
С другой стороны, запомненная версия будет работать:
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;
(не уверен, для чего предназначен s/.*E//r
)