如何使用ANTLR4解析带内环的WKT多边形字符串?
解决ANTLR4解析多内环WKT多边形的问题
这问题我之前踩过坑!你现在的核心问题是用Lexer规则直接匹配整个POLYGON结构,但Lexer的正则匹配是贪婪的,会把所有内部的括号、逗号都一股脑吞掉,导致ANTLR找不到预期的闭合右括号,自然就报错了。
为什么原来的规则不行?
你修改后的规则POLYGON: ('polygon'|'POLYGON')'(('[0-9:,-.eTZ" \(\)]+'))';里,[0-9:,-.eTZ" \(\)]+是贪婪匹配,会从第一个(开始,一直读到整个字符串的最后一个)才停下来。这就意味着,当你有多个内环时,Lexer会把所有环的内容都当成一个整体,Parser期望的闭合)已经被Lexer吃掉了,当然会提示找不到右括号。
正确的解决方案:拆分Lexer和Parser规则
WKT的多边形是嵌套结构化语法,这种场景下不能靠Lexer单独处理,必须让Lexer识别基础Token,再用Parser来定义嵌套的结构逻辑。具体步骤如下:
1. 编写Lexer规则(识别最小单元)
Lexer只负责拆分出关键字、括号、逗号、坐标值这些基础Token:
lexer grammar WKTLexer; // WKT关键字 POLYGON_KEYWORD: 'polygon' | 'POLYGON'; // 标点符号 LPAREN: '('; RPAREN: ')'; COMMA: ','; // 匹配坐标值:支持浮点数、带引号的日期时间(可根据需求扩展格式) COORD_VALUE: // 浮点数格式(支持科学计数法) (DIGIT+ ('.' DIGIT*)? | '.' DIGIT+) ('e' '-'? DIGIT+)? // 带引号的日期时间(比如"2024-05-20T12:30:00Z") | '"' [0-9T:-.Z]+ '"'; // 辅助片段 fragment DIGIT: [0-9]; // 跳过空白符 WS: [ \t\r\n]+ -> skip;
2. 编写Parser规则(定义结构化逻辑)
Parser负责把Lexer输出的Token组合成合法的多边形结构,处理嵌套的环:
parser grammar WKTParser; options { tokenVocab=WKTLexer; } // 入口规则 wkt: polygon EOF; // 多边形结构:关键字 + 外层括号 + 多个环(用逗号分隔) polygon: POLYGON_KEYWORD LPAREN ring (COMMA ring)* RPAREN; // 环结构:括号包裹的多个坐标点(用逗号分隔) ring: LPAREN coordinate (COMMA coordinate)* RPAREN; // 坐标点:两个值(比如经度+纬度,时间+数值等) coordinate: COORD_VALUE COORD_VALUE;
为什么这样能解决问题?
- Lexer只处理最小的单元,不会贪婪吞掉整个结构,每个括号、逗号都是独立的Token;
- Parser的
ring规则专门处理单个环的括号嵌套,polygon规则则负责组合多个环,完美适配多内环的WKT格式; - 后续如果要扩展支持POINT、LINESTRING等其他WKT类型,只需要在Parser里添加对应的规则即可,扩展性极强。
额外提示
如果你的坐标值格式有更复杂的要求(比如特殊时区格式、带正负号的数值),可以直接修改COORD_VALUE的规则,比如给浮点数添加正负号支持:
COORD_VALUE: ('+' | '-')? (DIGIT+ ('.' DIGIT*)? | '.' DIGIT+) ('e' ('+' | '-')? DIGIT+)? | '"' [0-9T:-.Z]+ '"';
内容的提问来源于stack exchange,提问作者Bằng Rikimaru
相关产品推荐
相关产品推荐

