如何用ANTLR构建支持单选项不重复的查询语法?
解决ANTLR语法中限制to/from/subject仅出现一次的问题
需求回顾
需要构建的ANTLR语法需满足:
- 支持
toAddress、fromAddress、subject三个可选部分 - 每个部分最多出现一次,顺序不受限制
- 同时支持纯自由文本输入(无上述三个关键字的内容)
原语法的核心问题
原规则(toAddress | fromAddress | subject)*使用通配符*,会允许同一部分重复出现(比如多次输入to:),违反了"每个部分仅能出现一次"的要求。此外,词法规则NAME和ANYTHING存在定义重叠,会导致词法分析冲突;addressValue的可选定义可能允许无内容的关键字输入(如to:后面空着)。
修正后的完整语法
grammar SearchQuery; // 主规则:覆盖所有合法的无重复组合,或纯自由文本 searchQueryLang : ( toAddress (fromAddress subject? | subject fromAddress?)? | fromAddress (toAddress subject? | subject toAddress?)? | subject (toAddress fromAddress? | fromAddress toAddress?)? )? | freeText ; // 各关键字规则,确保后面跟着对应的值 toAddress: TO addressValue; fromAddress: FROM addressValue; subject: SUBJECT subjectValue; // 自由文本:任意非关键字开头的内容 freeText: FREE_TEXT+; // 词法规则:关键字(忽略大小写) TO: T O ':'; FROM: F R O M ':'; SUBJECT: S U B J E C T ':'; // 空格跳过 SPACES: [ \u000B\t\r\n] -> skip; // 地址值:支持邮箱等格式,禁止包含关键字前缀 addressValue: (CHARACTERS)+; // 主题值:支持带双引号的内容,处理内部不含未转义引号的情况 subjectValue: QUOTED_STRING | CHARACTERS+; // 通用字符集(排除关键字开头的情况,避免与关键字冲突) CHARACTERS: ~[ \t\r\n"]+; // 带引号的字符串 QUOTED_STRING: '"' (~["\\] | ESCAPE_SEQUENCE)* '"'; ESCAPE_SEQUENCE: '\\' ["\\]; // 忽略大小写的字符定义 fragment A: [aA]; fragment B: [bB]; fragment C: [cC]; fragment E: [eE]; fragment F: [fF]; fragment H: [hH]; fragment J: [jJ]; fragment M: [mM]; fragment O: [oO]; fragment R: [rR]; fragment S: [sS]; fragment T: [tT]; fragment U: [uU];
关键修改说明
- 主规则重构:通过枚举所有合法的无重复组合,确保
to/from/subject每个最多出现一次,且顺序任意。同时保留了空输入的合法性(对应全自由文本的情况)。 - 词法规则优化:
- 合并了原
NAME和ANYTHING的重叠定义,用CHARACTERS统一处理通用文本 - 增加了
QUOTED_STRING和转义序列,支持带引号的主题内容 - 关键字使用片段定义,支持大小写不敏感的输入(如
TO:/to:都合法)
- 合并了原
- 值规则修正:将
addressValue改为必填,避免关键字后无内容的无效输入;subjectValue同时支持带引号和普通文本两种格式。
内容的提问来源于stack exchange,提问作者TTTis
相关产品推荐
相关产品推荐

