如何使用Marpa:r2解析单引号字符串?在下面的代码中,单引号字符串在解析时附加'\‘。
代码:
use strict;
use Marpa::R2;
use Data::Dumper;
my $grammar = Marpa::R2::Scanless::G->new(
{ default_action => '[values]',
source => \(<<'END_OF_SOURCE'),
lexeme default = latm => 1
:start ::= Expression
# include begin
Expression ::= Param
Param ::= Unquoted
| ('"') Quoted ('"')
| (') Quoted (')
:discard ~ whitespace
whitespace ~ [\s]+
Unquoted ~ [^\s\/\(\),&:\"~]+
Quoted ~ [^\s&:\"~]+
END_OF_SOURCE
});
my $input1 = 'foo';
#my $input2 = '"foo"';
#my $input3 = '\'foo\'';
my $recce = Marpa::R2::Scanless::R->new({ grammar => $grammar });
print "Trying to parse:\n$input1\n\n";
$recce->read(\$input1);
my $value_ref = ${$recce->value};
print "Output:\n".Dumper($value_ref);产出的:
Trying to parse:
foo
Output:
$VAR1 = [
[
'foo'
]
];
Trying to parse:
"foo"
Output:
$VAR1 = [
[
'foo'
]
];
Trying to parse:
'foo'
Output:
$VAR1 = [
[
'\'foo\''
]
]; (don't want it to be parsed like this)以上是所有输入的输出,我不希望第三个输入被附加'\‘和单引号。我希望它像OUTPUT2一样被解析。请给我建议。
理想情况下,它应该选择单引号之间的内容,根据Param ::= (')引号(')
发布于 2018-05-01 09:38:07
关于数据的另一个答案是::Dumper输出是正确的。然而,你的语法不像你期望的那样起作用。
在解析输入'foo'时,Marpa将考虑三个Param替代方案。该位置的预测词汇是:
Unquoted ~ [^\s\/\(\),&:\"~]+'"'') Quoted ('是的,最后一个是字面上的) Quoted (,而不是任何包含单引号的东西。
即使是([']) Quoted ([']):由于最长的令牌匹配,未引用的were也将匹配整个输入,包括单引号。
像" foo "这样的输入(带有双引号)会发生什么?现在,只有'"' lexeme匹配,然后任何空格都会被丢弃,然后引用的lexeme匹配,然后任何空格都被丢弃,然后关闭"被匹配。
为了防止这种跳过空格的行为,并防止由于LATM而首选未引号的规则,将引号字符串描述为词汇是有意义的。例如:
Param ::= Unquoted | Quoted
Unquoted ~ [^'"]+
Quoted ~ DQ | SQ
DQ ~ '"' DQ_Body '"' DQ_Body ~ [^"]*
SQ ~ ['] SQ_Body ['] SQ_Body ~ [^']*这些词汇将包括任何引号和转义,因此您需要后处理该词的内容。您可以使用事件系统(在概念上是干净的,但实现起来有点麻烦)来完成这一任务,或者添加在解析计算期间执行此处理的操作。
因为lexemes不能有操作,所以通常最好添加一个代理产品:
Param ::= Unquoted | Quoted
Unquoted ~ [^'"]+
Quoted ::= Quoted_Lexeme action => process_quoted
Quoted_Lexeme ~ DQ | SQ
DQ ~ '"' DQ_Body '"' DQ_Body ~ [^"]*
SQ ~ ['] SQ_Body ['] SQ_Body ~ [^']*这样,这个动作就可以做如下的事情:
sub process_quoted {
my (undef, $s) = @_;
# remove delimiters from double-quoted string
return $1 if $s =~ /^"(.*)"$/s;
# remove delimiters from single-quoted string
return $1 if $s =~ /^'(.*)'$/s;
die "String was not delimited with single or double quotes";
}发布于 2018-04-30 21:44:23
您的结果不包含\',而是包含'。Dumper只是将结果格式化成那样,因此可以清楚地知道字符串中的内容和不包含的内容。
您可以自己测试这种行为:
use Data::Dumper;
my $tick = chr(39);
my $back = chr(92);
print "Tick Dumper: " . Dumper($tick);
print "Tick Print: " . $tick . "\n";
print "Backslash Dumper: " . Dumper($back);
print "Backslash Print: " . $back . "\n";您可以在这里看到一个演示:https://ideone.com/d1V8OE
如果不希望输出包含单引号,则可能需要自己从输入中删除它们。
发布于 2018-05-01 08:33:05
我不太熟悉Marpa::R2,但您是否可以尝试使用Expression规则的操作:
Expression ::= Param action => strip_quotes然后,实现一个简单的报价脱衣舞娘如下:
sub MyActions::strip_quotes {
@{$_[1]}[0] =~ s/^'|'$//gr;
}https://stackoverflow.com/questions/50108574
复制相似问题