我有一个需要解析的字符串,对于正则表达式来说太重了。正则表达式不能很好地找到平衡的匹配项...尽管任务很简单,因为每个字符串可以包含三种类型的信息:
我需要对字符串进行插值,以便可以用程序生成的内容替换变量和函数,但是要保留适当的位置,以便保留任意文本(包括空格)。
我发现这是学习ANTLR的绝佳机会,但是我正在努力使它起作用。
我基本上在三件事上有问题:
.+
,.+?
,~[$<]
。几个测试字符串:
"The length of the COMPUTER environment variable is $Length(<Env:COMPUTER>)"
"The last 10 chars of the COMPUTER environment is $Substring($Length(<Env:COMPUTER>)-10, $Length(<Env:COMPUTER>))"
到目前为止,这是我的代码:
grammar Output;
start
: (expr)* ;
expr
: expr expr
| VAR
| FUNC '(' commaexpr ')'
;
commaexpr
: expr
| commaexpr ',' commaexpr
;
FUNC: '$' ID ;
VAR : '<' ID '>' ;
fragment ID : [a-zA-Z] | [a-zA-Z][a-zA-Z0-9:]+ ;
WS : [\r\n]+ -> skip ;
编辑:
我已经能够在这方面有所进步。好像我有解决办法,有点。不确定我的解决方案是否是最佳选择:
grammar Output;
start
: (expr)* ;
expr
: expr expr
| variable
| function
| text
;
variable
: VAR
;
function
: FUNC '(' commaexpr ')'
;
commaexpr
: WS? expr WS?
| commaexpr ',' commaexpr
;
text: TEXT+ ;
FUNC: '$' ID ;
VAR : '<' ID '>' ;
fragment ID : [a-zA-Z] | [a-zA-Z][a-zA-Z0-9:]+ ;
TEXT: .+?;
NL : [\r\n]+ -> skip ;
WS: [ ]+ ;
这样做有什么陷阱吗?我看到text
表达式是一个字符列表,而不是字符串,但这对我有用,因为我可以在访问者中对它们使用GetText()来获取实际数据。
结果
我选择了Bart's answer。
最终代码,ANTLR代码以及与此相关的访客在这里:https://github.com/IntelliSearch/FlexVersion/tree/master/IntelliSearch.FlexVersion.OutputParser
这里是https://github.com/IntelliSearch/FlexVersion/blob/master/IntelliSearch.FlexVersion/OutputVisitor.cs
万一链接消失,这是ANTLR g4文件:
grammar Output;
start
: expr* EOF
;
expr
: function
| variable
| text
;
function
: FUNC '(' params ')';
variable
: VAR;
params
: expr+ ( ',' expr+ )*
;
text
: OTHER+
;
FUNC : '$' ID;
VAR : '<' ID '>';
OPEN_PAR : '(';
CLOSE_PAR : ')';
COMMA : ',';
OTHER : . ;
fragment ID : [a-zA-Z] [a-zA-Z0-9:]* ;
如您所见,我还抛弃了运算符(++-/ *),因为这只应该在params中允许,但是后来我不确定那是否真的很聪明,所以我去了一种方法也是通过特定的$函数解决的。
答案 0 :(得分:1)
在词法分析器中,.+?
将始终只使用一个字符,因此请注意删除+?
部分。
我有这样的想法:
grammar Output;
start
: expr* EOF
;
expr
: FUNC '(' params ')'
| expr ( MULT | DIV ) expr
| expr ( PLUS | MINUS ) expr
| VAR
| ignore
;
params
: expr+ ( ',' expr+ )*
;
ignore
: OTHER+
;
FUNC : '$' ID;
VAR : '<' ID '>';
OPEN_PAR : '(';
CLOSE_PAR : ')';
MULT : '*';
DIV : '/';
MINUS : '-';
PLUS : '+';
OTHER : . ;
fragment ID : [a-zA-Z] [a-zA-Z0-9:]* ;
我刚刚看到了您自己的解决方案,但是如果按您希望的方式工作,那很好。