ANTLR4:如何解析 WKT 多边形字符串?
ANTLR4: How to parse a WKT polygon string?
我在 java 中使用 ANLTR4,我可以像这样解析 WKT 多边形字符串
polygon((20 30, 30 40, 50 60, 20 30))
使用这个词法分析器:
POLYGON: ('polygon'|'POLYGON')'(('[0-9:,-.eTZ" ]+'))';
因为polygon(( ))里面的数字可以是datetime或者float所以它包含了一些字符
但是,我无法像这样解析具有内部多边形的多边形
polygon((20 30, 30 40, 50 60, 20 30), (20 30, 30 40, 50 60, 20 30), (20 30, 30 40, 50 60, 20 30))
当我尝试在 Lexer 中添加 () 时,例如:
POLYGON: ('polygon'|'POLYGON')'(('[0-9:,-.eTZ" \(\)]+'))';
Java 抛出异常,用 .
找不到“)”
我该怎么做才能让 ANTLR4 可以解析 polygon((), (), (), ...)?
我认为你不应该只用词法分析器来做。您应该使用词法分析器拆分为符号;例如'polygon'
、'('
、')'
、','
、<number>
、<date>
等。然后实现一个语法来处理大规模语法;例如
<polygon> ::= 'polygon' '(' <list> ')'
<list> ::= '(' ')' |
'(' <element> ( ',' <element> ) * ')'
<element> ::= <number> | <date>
(我使用的元语法有点像 EBNF ....)
仅使用没有语法的基于正则表达式的词法分析器的问题是:
- 正则表达式难以阅读/难以验证
- 你没有得到解析树
- 您没有收到任何有意义的解析器错误
- 正则表达式越复杂,您就越有可能 运行 遇到性能问题;例如https://www.regular-expressions.info/catastrophic.html
词法分析器应该只定义语言的基本构建块。多边形、列表等应定义为解析器规则。
像这样的事情应该让你开始:
grammar WKT;
parse
: polygon EOF
;
polygon
: POLYGON '(' ( points ( ',' points )* )? ')'
;
points
: '(' ( value value ( ',' value value )* )? ')'
;
value
: INT
| FLOAT
| DATE_TIME
;
POLYGON
: [pP] [oO] [lL] [yY] [gG] [oO] [nN]
;
INT
: DIGITS
;
FLOAT
: DIGITS '.' DIGITS
;
DATE_TIME
: D D D D '-' D D '-' D D 'T' D D ':' D D ':' D D [+-] D D ':' D D
| D D D D '-' D D '-' D D 'T' D D ':' D D ':' D D 'Z'
| D D D D D D D D 'T' D D D D D D 'Z'
;
SPACES
: [ \t\r\n]+ -> skip
;
fragment DIGITS
: D+
;
fragment D
: [0-9]
;
以下输入:POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))
将按如下方式解析:
我在 java 中使用 ANLTR4,我可以像这样解析 WKT 多边形字符串
polygon((20 30, 30 40, 50 60, 20 30))
使用这个词法分析器:
POLYGON: ('polygon'|'POLYGON')'(('[0-9:,-.eTZ" ]+'))';
因为polygon(( ))里面的数字可以是datetime或者float所以它包含了一些字符
但是,我无法像这样解析具有内部多边形的多边形
polygon((20 30, 30 40, 50 60, 20 30), (20 30, 30 40, 50 60, 20 30), (20 30, 30 40, 50 60, 20 30))
当我尝试在 Lexer 中添加 () 时,例如:
POLYGON: ('polygon'|'POLYGON')'(('[0-9:,-.eTZ" \(\)]+'))';
Java 抛出异常,用 .
找不到“)”我该怎么做才能让 ANTLR4 可以解析 polygon((), (), (), ...)?
我认为你不应该只用词法分析器来做。您应该使用词法分析器拆分为符号;例如'polygon'
、'('
、')'
、','
、<number>
、<date>
等。然后实现一个语法来处理大规模语法;例如
<polygon> ::= 'polygon' '(' <list> ')'
<list> ::= '(' ')' |
'(' <element> ( ',' <element> ) * ')'
<element> ::= <number> | <date>
(我使用的元语法有点像 EBNF ....)
仅使用没有语法的基于正则表达式的词法分析器的问题是:
- 正则表达式难以阅读/难以验证
- 你没有得到解析树
- 您没有收到任何有意义的解析器错误
- 正则表达式越复杂,您就越有可能 运行 遇到性能问题;例如https://www.regular-expressions.info/catastrophic.html
词法分析器应该只定义语言的基本构建块。多边形、列表等应定义为解析器规则。
像这样的事情应该让你开始:
grammar WKT;
parse
: polygon EOF
;
polygon
: POLYGON '(' ( points ( ',' points )* )? ')'
;
points
: '(' ( value value ( ',' value value )* )? ')'
;
value
: INT
| FLOAT
| DATE_TIME
;
POLYGON
: [pP] [oO] [lL] [yY] [gG] [oO] [nN]
;
INT
: DIGITS
;
FLOAT
: DIGITS '.' DIGITS
;
DATE_TIME
: D D D D '-' D D '-' D D 'T' D D ':' D D ':' D D [+-] D D ':' D D
| D D D D '-' D D '-' D D 'T' D D ':' D D ':' D D 'Z'
| D D D D D D D D 'T' D D D D D D 'Z'
;
SPACES
: [ \t\r\n]+ -> skip
;
fragment DIGITS
: D+
;
fragment D
: [0-9]
;
以下输入:POLYGON ((35 10, 45 45, 15 40, 10 20, 35 10), (20 30, 35 35, 30 20, 20 30))
将按如下方式解析: