【发布时间】:2016-08-30 23:13:26
【问题描述】:
我想解析纯文本 cmets 并在其中查找某些标签。我正在寻找的标签类型如下所示:
<name#1234>
其中“name”是一个 [a-z] 字符串(来自固定列表),“1234”代表一个 [0-9]+ 数字。这些标签可以在字符串中出现零次或多次,并被任意其他文本包围。例如,以下字符串都是有效的:
"Hello <foo#56> world!"
"<bar#1>!"
"1 < 2"
"+<baz#99>+<squid#0> and also<baz#99>.\n\nBy the way, maybe <foo#9876>"
以下字符串均无效:
"1 < 2"
"<foo>"
"<bar#>"
"Hello <notinfixedlist#1234>"
最后一个无效,因为“notinfixedlist”不是受支持的命名标识符。
例如,我可以使用简单的正则表达式轻松解析它(为了简单起见,我省略了命名组):
<[a-z]+#\d+>
或直接指定固定列表:
<(foo|bar|baz|squid)#\d+>
但我想使用 antlr 有几个原因:
- 我希望任何与该格式不匹配的内容都会导致解析错误,因此如果文本包含“”但与模式不匹配,则会失败。这些字符必须转义为“<”和“>”如果它不是标签,则分别。
- 将来我可能会扩展它以支持其他类型的模式(例如:“{foo+666}”或“[[@1234]]”,并希望避免正则表达式语句的爆炸式增长。具有单一语法我可以扩展的文件会很棒。
- 我喜欢 antlr4 实现了访问者模式,当遇到特定类型的标签时我的代码会被调用,而不必将不同的正则表达式组合在一起。
如何使用 antlr4 实现这样的语法?我见过的大多数示例都是针对整个文本遵循精确规则的语言,而我只希望语法适用于任意文本中的匹配模式。
我想出了这个,我认为这是正确的:
grammar Tags;
parse
: ( tag | text )*
;
tag
: '<' fixedlist '#' ID '>'
;
fixedlist
: 'foo'
| 'bar'
| 'baz'
| 'squid';
text
: ~('<' | '>')+
;
ID
: [0-9]+
;
这对吗?
【问题讨论】:
-
问题表述得很好,但不太适合 SO,因为它主要是基于意见的。
-
好点。我将修改问题以具体询问如何在antlr中实现。
-
您的词法分析器可能只有两条规则:一个 TAG 和一个 CHAR,然后语法就是一个
(TAG | CHAR) *。
标签: c# regex parsing antlr4 text-parsing