gpt4 book ai didi

regex - 如何访问由递归Perl正则表达式捕获的组?

转载 作者:行者123 更新时间:2023-12-03 14:55:38 25 4
gpt4 key购买 nike

我正在尝试用perl regex修改一个简单的语法(请注意,这不是供生产使用的,只是为了提供编辑提示/完成内容而进行的快速分析)。例如,

my $GRAMMAR = qr{(?(DEFINE)
(?<expr> \( (?&expr) \) | (?&number) | (?&var) | (?&expr) (?&op) (?&expr) )
(?<number> \d++ )
(?<var> [a-z]++ )
(?<op> [-+*/] )
)}x;


我希望能够以此运行

$expr =~ /$GRAMMAR(?&expr)/;


然后访问所有变量名称。但是,根据 perlre


请注意,在递归返回之后无法访问在递归内匹配的捕获组,因此捕获组的额外层是必需的。因此,即使$ + {NAME}被定义,也不会定义$ + {NAME_PAT}。


因此,显然这是不可能的。我可以尝试使用 (?{ code })块将变量名保存到哈希表中,但这不考虑回溯(即,即使变量回溯过去,赋值的副作用仍然存在)。

有没有办法让给定的命名捕获组捕获所有内容,包括递归匹配?还是我需要手动挖掘各个片段(从而复制所有图案)?

最佳答案

Regexp::Grammars解决的缺点之一就是必须添加捕获和回溯机制。

但是,您问题中的语法为left-recursive,Perl正则表达式和递归下降解析器均不会解析该语法。

使语法适应Regexp::Grammars并排除左递归产生

my $EXPR = do {
use Regexp::Grammars;
qr{
^ <Expr> $

<rule: Expr> <Term> <ExprTail>
| <Term>

<rule: Term> <Number>
| <Var>
| \( <MATCH=Expr> \)

<rule: ExprTail> <Op> <Expr>

<token: Op> \+ | \- | \* | \/

<token: Number> \d++

<token: Var> [a-z]++
}x;
};


请注意,此简单语法为所有运算符赋予了相同的优先级,而不是“请打扰我亲爱的萨莉姨妈”。

您想要提取所有变量名,因此可以像这样遍历AST

sub all_variables {
my($root,$var) = @_;

$var ||= {};
++$var->{ $root->{Var} } if exists $root->{Var};
all_variables($_, $var) for grep ref $_, values %$root;

wantarray ? keys %$var : [ keys %$var ];
}


并用打印结果

if ("(a + (b - c))" =~ $EXPR) {
print "[$_]\n" for sort +all_variables \%/;
}
else {
print "no match\n";
}


另一种方法是为 Var规则安装自动操作,该规则记录成功解析变量的名称。

package JustTheVarsMaam;

sub new { bless {}, shift }

sub Var {
my($self,$result) = @_;
++$self->{VARS}{$result};
$result;
}

sub all_variables { keys %{ $_[0]->{VARS} } }

1;


称这个为

my $vars = JustTheVarsMaam->new;
if ("(a + (b - c))" =~ $EXPR->with_actions($vars)) {
print "[$_]\n" for sort $vars->all_variables;
}
else {
print "no match\n";
}


无论哪种方式,输出都是

[一个]
[b]
[C]

关于regex - 如何访问由递归Perl正则表达式捕获的组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17602554/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com