如何使用Marpa::R2 Perl从大表达式中解析识别双引号字符串
解决Marpa::R2解析双引号字符串的问题
看起来你的核心问题是STRING规则的定义不正确——原规则只是排除了部分字符,没有明确匹配双引号的边界,也没处理字符串内部的转义双引号,导致无法正确识别标准的双引号字符串(比如"hello \"world\"")。下面是具体的修复方案:
1. 修正双引号字符串的语法规则
Marpa的Scanless语法需要明确定义双引号字符串的结构:从起始双引号开始,允许转义的双引号和其他非双引号字符,最后以结束双引号收尾。替换你原有的STRING规则为以下内容:
# 定义双引号字符串的完整结构 STRING ::= DQUOTE STRING_CONTENT DQUOTE # 字符串内容:可以是转义的双引号,或者任意非双引号字符(零次或多次) STRING_CONTENT ::= (STRING_ESCAPE | [^"])* # 转义双引号:注意Perl和Marpa的双重转义 STRING_ESCAPE ::= '\\"' # 单独定义双引号符号,提高可读性 DQUOTE ::= '"'
关键细节说明:
- 用
DQUOTE明确匹配起始和结束的双引号,确保只有成对的双引号才会被识别为字符串的边界 STRING_CONTENT允许转义的双引号(\"),这样字符串内部的转义双引号不会被误判为字符串结束- 双重转义:因为Perl字符串会先解析一次转义,所以在Marpa的源字符串里,要写
'\\"'才能表示实际的\"序列
2. 完整的示例代码
把修正后的规则整合到你的代码中,补全原代码里省略的部分(比如OP、func的定义),完整代码如下:
use strict; use Marpa::R2; use Data::Dumper; my $grammar = Marpa::R2::Scanless::G->new({ default_action => '[values]', source => \<<'END_OF_SOURCE', :start ::= expression expression ::= expression OP expression | expression COMMA expression | func LPAREN PARAM RPAREN | PARAM PARAM ::= STRING | REGEX_STRING :discard ~ sp sp ~ [\s]+ COMMA ~ [,] # 补全OP的定义(假设是逻辑运算符&或|) OP ~ [&|] # 定义函数名规则 func ~ [a-zA-Z_][a-zA-Z0-9_]* LPAREN ~ '(' RPAREN ~ ')' # 修正正则字符串规则(处理转义的/) REGEX_STRING ~ '/' ( [^/] | '\\/' )* '/' # 修正后的双引号字符串规则 STRING ::= DQUOTE STRING_CONTENT DQUOTE STRING_CONTENT ::= (STRING_ESCAPE | [^"])* STRING_ESCAPE ::= '\\"' DQUOTE ::= '"' END_OF_SOURCE }); # 测试带转义双引号的输入 my $input = q{func("hello \"world\"", "another string", "single \"quote\" inside")}; my $recce = Marpa::R2::Scanless::R->new({ grammar => $grammar }); $recce->read(\$input); if (my $value_ref = $recce->value) { print "解析结果:\n"; print Dumper($$value_ref); } else { print "解析失败!\n"; }
3. 额外注意事项
- 如果你的
REGEX_STRING规则也存在类似的转义问题(比如正则内部的/需要转义),也要同步修正,示例中已经处理了这种情况 - 确保
:discard ~ sp规则不会影响字符串内部的空格——因为字符串内部的空格属于STRING_CONTENT的一部分,不会被discard规则忽略,这一点是正确的 - 如果你的表达式还有其他复杂结构(比如嵌套括号、更多运算符),可能需要调整规则的优先级,避免歧义
内容的提问来源于stack exchange,提问作者zubug55
相关产品推荐
相关产品推荐

