【发布时间】:2020-02-02 23:15:08
【问题描述】:
我正在尝试使用 ANTLR 创建一个 Lexer/Parser,它可以解析带有散布在其间的“标签”的纯文本。 这些标签由左括号 ({) 和右括号 (}) 表示,它们表示可以评估为字符串的 Java 对象,然后在原始输入中替换该字符串以创建各种动态模板。
这是一个例子: {player:name} 打招呼! {player:name} 应替换为玩家的名称并导致输出,即 Mark says hi!对于名为 Mark 的玩家。
现在我可以很好地识别和解析标签,我遇到的问题是后面的文本。 这是我使用的语法:
grammar : content+
content : tag
| literal
;
tag : player_tag
| <...>
| <other kinds of tags, not important for this example>
| <...>
;
player_tag : BRACKET_OPEN player_identifier SEMICOLON player_string_parameter BRACKET_CLOSE ;
player_string_parameter : NAME
| <...>
;
player_identifier : PLAYER ;
literal : NUMBER
| STRING
;
BRACKET_OPEN : '{';
BRACKET_CLOSE : '}';
PLAYER : 'player'
NAME : 'name'
NUMBER : <...>
STRING : (.+)? /* <- THIS IS THE PROBLEMATIC PART !*/
现在这个 STRING Lexer 定义应该匹配任何非空字符串,但问题是它过于贪婪,然后还消耗了标记规则所需的 { } 括号标记。 我尝试将其设置为 ~[{}]+ ,它应该与不包含 { } 括号的任何内容匹配,但与我也不理解的标签解析有关。 我可以将其设置为 [ a-zA-Z0-9!"§$%&/()= etc...]+ 但我真的不想将其限制为仅解析英式键盘上可用的字符(德语变音符号或法语口音以及其他语言必须使用的所有其他特殊字符!) 尽管我真的不喜欢它,但唯一有效的方法是强制字符串具有前缀和后缀,如下所示:
STRING : '\'' ~[}{]+ '\'' ;
这迫使我改变“{player:name} say hi!”的形式。到“{player:name}' say hi!'”,我真的非常想避免这样的限制,因为我必须考虑字符串本身中的文字 ' 字符,而且使用起来很难看。
我想到的两个解决方案如下: - 有什么方法可以匹配任意数量的未被词法分析器匹配的字符作为字符串令牌并将其传递给解析器?这样我就可以匹配所有的标签,然后说输入的其余部分只是纯文本,把它作为一个 STRING 令牌或其他东西还给我...... - ANTLR 是否支持前瞻和后瞻正则表达式,我可以匹配第一个 '{' 之前、最后一个 '}' 之后以及 '}' 和 '{' 之间的任何字符的任意数量的字符? 我试过了
STRING : (?<=})(.+)?(?={) ;
但我似乎无法获得正确的语法,因为它根本无法编译,这让我相信 ANTLR 不支持前瞻和后瞻语法,但我在互联网上找不到明确的答案这个问题。
有什么建议吗?
【问题讨论】:
标签: parsing antlr antlr4 regex-lookarounds