pyparsing - 如何预测不明确的语法(时间戳 with/without 时区解析)
pyparsing - how to lookahead for ambiguous grammar (timestamp with/without timezone parse)
我正在尝试使用 pyparsing 来解析 SQL 方言中的某些时间戳类型。
在这个特定的 sql 方言中,我们有两种时间戳类型 - 带时区和不带时区。
无时区示例:TIMESTAMP WITHOUT TIME ZONE
、TIMESTAMP(3)
、TIMESTAMP
、TIMESTAMP(3) WITHOUT TIME ZONE
带时区的示例:TIMESTAMP WITH TIME ZONE
、TIMESTAMP(9) WITH TIME ZONE
。如您所见,唯一的区别是需要明确定义带有时区的那些。
不幸的是,以下匹配不适用于 pyparsing:
(RPAR, LPAR, COMMA) = map(Suppress, "(),")
NUMS = Word(nums)
TIMESTAMP = CaselessKeyword("TIMESTAMP") +
Optional(RPAR + NUMS + LPAR) +
Optional(CaselessKeyword("WITHOUT TIME ZONE"))
TIMESTAMP_WITH_TIMEZONE = CaselessKeyword("TIMESTAMP") +
Optional(RPAR + NUMS + LPAR) +
CaselessKeyword("WITH TIME ZONE")
GRAMMAR = StringStart() + TIMESTAMP | TIMESTAMP_WITH_TIMEZONE + StringEnd()
GRAMMAR.parseString("TIMESTAMP WITHOUT TIMEZONE") # Works fine
GRAMMAR.parseString("TIMESTAMP WITH TIMEZONE") # fails
失败是:
File "/.../lib/python3.8/site-packages/pyparsing.py", line 3814, in parseImpl
raise ParseException(instring, loc, self.errmsg, self)
pyparsing.ParseException: Expected end of text, found 'W' (at char 10), (line:1, col:11)
我认为这个错误可能是因为这个语法需要 1 级前瞻来判断某物是否是 TIMESTAMP WITH TIMESTAMP
和 TIMESTAMP WITHOUT TIMESTAMP
。当它无法匹配 WITH TIMESTAMP
时,它需要 TIMESTAMP
并结束(显然失败的原因不是字符串的结尾)。在这种情况下我该怎么办? pyparsing 是否具有解决此问题的前瞻能力?
一条规则比另一条更具体,因为它不涉及 Optional 关键字。连词是有序的,因此我们必须将语法定义为:
GRAMMAR = ... + TIMESTAMP_WITH_TIMEZONE | TIMESTAMP + ...
相反。我尝试了 FollowedBy,但效果不是很好。
您还需要在内部“|”周围使用括号选择:
>>> expr = pp.Literal("a") + pp.Literal("b") | pp.Literal("c") + pp.Literal("d")
>>> expr
{{"a" "b"} | {"c" "d"}}
应该是:
GRAMMAR = StringStart() + (TIMESTAMP_WITH_TIMEZONE | TIMESTAMP) + StringEnd()
我正在尝试使用 pyparsing 来解析 SQL 方言中的某些时间戳类型。
在这个特定的 sql 方言中,我们有两种时间戳类型 - 带时区和不带时区。
无时区示例:TIMESTAMP WITHOUT TIME ZONE
、TIMESTAMP(3)
、TIMESTAMP
、TIMESTAMP(3) WITHOUT TIME ZONE
带时区的示例:TIMESTAMP WITH TIME ZONE
、TIMESTAMP(9) WITH TIME ZONE
。如您所见,唯一的区别是需要明确定义带有时区的那些。
不幸的是,以下匹配不适用于 pyparsing:
(RPAR, LPAR, COMMA) = map(Suppress, "(),")
NUMS = Word(nums)
TIMESTAMP = CaselessKeyword("TIMESTAMP") +
Optional(RPAR + NUMS + LPAR) +
Optional(CaselessKeyword("WITHOUT TIME ZONE"))
TIMESTAMP_WITH_TIMEZONE = CaselessKeyword("TIMESTAMP") +
Optional(RPAR + NUMS + LPAR) +
CaselessKeyword("WITH TIME ZONE")
GRAMMAR = StringStart() + TIMESTAMP | TIMESTAMP_WITH_TIMEZONE + StringEnd()
GRAMMAR.parseString("TIMESTAMP WITHOUT TIMEZONE") # Works fine
GRAMMAR.parseString("TIMESTAMP WITH TIMEZONE") # fails
失败是:
File "/.../lib/python3.8/site-packages/pyparsing.py", line 3814, in parseImpl
raise ParseException(instring, loc, self.errmsg, self)
pyparsing.ParseException: Expected end of text, found 'W' (at char 10), (line:1, col:11)
我认为这个错误可能是因为这个语法需要 1 级前瞻来判断某物是否是 TIMESTAMP WITH TIMESTAMP
和 TIMESTAMP WITHOUT TIMESTAMP
。当它无法匹配 WITH TIMESTAMP
时,它需要 TIMESTAMP
并结束(显然失败的原因不是字符串的结尾)。在这种情况下我该怎么办? pyparsing 是否具有解决此问题的前瞻能力?
一条规则比另一条更具体,因为它不涉及 Optional 关键字。连词是有序的,因此我们必须将语法定义为:
GRAMMAR = ... + TIMESTAMP_WITH_TIMEZONE | TIMESTAMP + ...
相反。我尝试了 FollowedBy,但效果不是很好。
您还需要在内部“|”周围使用括号选择:
>>> expr = pp.Literal("a") + pp.Literal("b") | pp.Literal("c") + pp.Literal("d")
>>> expr
{{"a" "b"} | {"c" "d"}}
应该是:
GRAMMAR = StringStart() + (TIMESTAMP_WITH_TIMEZONE | TIMESTAMP) + StringEnd()