编写lexer解析自定义DASH KEY EQUAL数据格式遇连字符匹配问题求助
问题根因
你当前的词法规则存在两个核心问题:
- 缺少
KEY的显式规则,且未限制KEY的允许字符范围 - Lexer默认采用贪婪匹配策略,由于
IDENTIFIER规则包含了-字符,会把本应作为下一个键值对起始标记的-也划入IDENTIFIER的匹配范围,导致吞字符。
解决方案
方案1:使用多模式Lexer(最稳妥,无需修改格式规范)
主流Lexer工具(ANTLR、Lex等)都支持模式切换能力,你可以根据当前解析状态切换匹配规则,完全避免规则冲突:
// 初始默认模式,只匹配键值对起始的短横线 DASH : '-' -> pushMode(KEY_MODE); mode KEY_MODE; // 限制KEY只能由字母、数字、下划线组成,不可包含-、=等特殊符号 KEY : [a-zA-Z0-9_]+; // 匹配到等号后切换到IDENTIFIER匹配模式 EQUAL : '=' -> mode(IDENTIFIER_MODE); mode IDENTIFIER_MODE; // 非贪婪匹配,直到碰到下一个键值对起始(-后面跟合法KEY首字符)或文件结束 IDENTIFIER : [a-zA-Z0-9 \-_<>@:.()/]+? (?= '-' [a-zA-Z0-9_] | EOF) -> popMode, popMode;
这个方案可以完美适配你现有的格式规范,连续的键值对比如-key1=val-123-key2=test-456也能正确拆分。
方案2:调整规则优先级+限定KEY范围(无需多模式,适合简单Lexer)
如果你的Lexer不支持多模式,可以调整规则顺序,且明确KEY的字符范围:
// 规则顺序优先级从上到下,优先匹配分隔符、KEY,最后匹配IDENTIFIER DASH : '-'; EQUAL : '='; // KEY必须不包含-、=,保证Lexer可以正确识别下一个键值对的起始 KEY : [a-zA-Z0-9_]+; IDENTIFIER : [a-zA-Z0-9 \-_<>@:.()/]+?;
这个方案需要注意:必须保证KEY的字符集和IDENTIFIER的分隔符(DASH)没有重叠,否则仍然会有匹配冲突。
方案3:增加转义规则(适合愿意调整格式规范的场景)
如果可以修改格式约定,你可以要求IDENTIFIER内部的-需要转义为\-,分隔用的-不转义,规则如下:
DASH : '-'; EQUAL : '='; KEY : [a-zA-Z0-9_]+; // 匹配转义的短横线,或者其他允许的非-字符 IDENTIFIER : ( '\\-' | [a-zA-Z0-9 _<>@:.()/] )+;
这个方案规则最简单,没有模式依赖,代价是需要用户编写内容时转义内部的短横线。
内容的提问来源于stack exchange,提问作者Peter Cheung
相关产品推荐
相关产品推荐

