我们尝试以以下形式解析查询:
Taiwan OR China
Taiwan OR "Republic of China"
本质上,像OR/AND/NOT这样的二元运算符将用于构造此类查询,引号用于标记包含多个单词的术语。然后,我们的目标是在此处提取各个名称:
- 第一种情况下的台湾和中国
- 第二种情况下的台湾和中华民国
(问题更复杂,但这是第一个里程碑(
从基础知识开始,对于第一个用例,我们将提供以下内容
grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
: WORD
;
WORD : ('a' .. 'z' | 'A' .. 'Z')+ ;
WS : [ trn]+ -> skip ;
当试图扩展它以捕获引号并处理引号内术语的空格时,我们有点挣扎。
我们尝试了这样的事情:
grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
: WORD
| '"' NAME_WITH_SPACES '"'
;
WORD : ('a' .. 'z' | 'A' .. 'Z')+ ;
NAME_WITH_SPACES : ('a' .. 'z' | 'A' .. 'Z' | ' ')+ ;
WS : [ trn]+ -> skip ;
更具体地说,输出是:
line 1:0 mismatched input 'TAIWAN OR CHINA' expecting {'"', WORD}
分别:
line 1:0 extraneous input 'TAIWAN OR ' expecting {'"', WORD}
line 1:29 mismatched input '<EOF>' expecting {'AND', 'OR', 'NOT'}
我们理解在尝试在引号内包含空格时可能会有摩擦,同时跳过引号外的空格。
任何想法都会受到欢迎 - 作为新的两个,很难说如何适应这些围绕空白的冲突要求。
不,这个:
name
: WORD
| '"' NAME_WITH_SPACES '"'
;
...
NAME_WITH_SPACES : ('a' .. 'z' | 'A' .. 'Z' | ' ')+ ;
与以下不同:
name
: WORD
| NAME_WITH_SPACES
;
...
NAME_WITH_SPACES : '"' ('a' .. 'z' | 'A' .. 'Z' | ' ')+ '"' ;
在第一种情况下,像Taiwan OR "Republic of China"
这样的输入被标记如下:
Taiwan OR
(类型:NAME_WITH_SPACES("
Republic of China
(类型:NAME_WITH_SPACES("
因为 ANTLR 的词法分析器规则试图匹配尽可能多的字符。因此,如果您让引号包含在NAME_WITH_SPACES
词法分析器规则中:
NAME_WITH_SPACES : '"' ('a' .. 'z' | 'A' .. 'Z' | ' ')+ '"' ;
然后将输入Taiwan OR "Republic of China"
标记为:
Taiwan
(类型:单词(OR
(类型:或("Republic of China"
(类型:NAME_WITH_SPACES(
并且正确跳过带引号的标记之外的空格。
请注意,您可以这样编写它:
WORD : [a-zA-Z]+ ;
NAME_WITH_SPACES : '"' [a-zA-Z ]+ '"' ;
另请参阅此相关问答:ANTLR中解析器规则和词法分析器规则之间的实际区别?
进一步,我们尝试了以下内容:
grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
: WORD
| NAME_WITH_SPACES
;
WORD : ('a' .. 'z' | 'A' .. 'Z')+ ;
NAME_WITH_SPACES : '"' ('a' .. 'z' | 'A' .. 'Z' | ' ')+ '"' ;
WS : [ trn]+ -> skip ;
这似乎工作得很好,即使对我来说它似乎与我们第一次尝试没有奏效的语义相同:
grammar Query;
parse : expr EOF ;
expr : name binop name ;
binop : 'AND' | 'OR' | 'NOT' ;
name
: WORD
| '"' NAME_WITH_SPACES '"'
;
WORD : ('a' .. 'z' | 'A' .. 'Z')+ ;
NAME_WITH_SPACES : ('a' .. 'z' | 'A' .. 'Z' | ' ')+ ;
WS : [ trn]+ -> skip ;