解决lark中字符串和数字的歧义
Resolve ambiguity between strings and numbers in lark
我正在为类似 YAML 的序列化格式编写语法。我正在使用 LALR 解析器。我在解析标量时遇到了障碍。标量可以是字符串或数字(让我们保持简单,只使用小数或浮点数)。这是我目前所拥有的,我只保留了相关的内容:
pair: pair_key ":" _value
_value: scalar | collection
scalar : (string | number) _NL+
string : WORD+
number : DECIMAL | FLOAT
DECIMAL : /0|[1-9]\d*/i
FLOAT: /((\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i
WORD: /[^-:#()\[\]{}\n\s]+/
// NEWLINE
_NL: /(\r?\n[\t ]*)+/
%import common.WS_INLINE
%ignore WS_INLINE
一个字符串是一个或多个单词。一个 WORD 可以包含任何字符,除了我放在 WORD 正则表达式的否定集中的字符。我希望我的字符串能够包含数字并且仍然被解析为字符串,这就是为什么我的 WORD 否定集中没有数字的原因。问题在于当字符串以这样的数字开头时:
test_strings = """
a : 28 should be parsed as string
b : 28
"""
解析器在看到开头为 28 时无法决定是解析数字还是解析单词。
这是我得到的:
top_map
pair
pair_key
string a
scalar
string
28
should
be
parsed
as
string
pair
pair_key
string b
scalar
string 28
预计:
top_map
pair
pair_key
string a
scalar
string
28
should
be
parsed
as
string
pair
pair_key
string b
scalar
number 28
我该如何解决这个歧义?有没有办法只使用语法来做到这一点?请注意,我不希望我的字符串被引号或其他符号包围以便能够识别它们。
编辑
我已经在我的号码规则中使用更高的优先级解决了这个问题:
string : number WORD+ | WORD+
number.2 : DECIMAL | FLOAT
DECIMAL.2 : /0|[1-9]\d*/i
FLOAT.2: /((\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i
WORD: /[^-:#()\[\]{}\n\s]+/
这样,数字将被解析为数字而不是 WORD。以数字开头的字符串后面必须有 WORD。所以在这个修改版本中没有字符串只是一个数字。
在我看来你应该保持语法原样,并在解析完成后将字符串转换为数字(如果有效)。
您仍然可以使用显式 number
规则,它可能会影响解析的上下文,但这里的歧义是可以在事后解决的,这将是最简单的解决方案。
为了完整起见,另一种解决方案是将整个字符串设为单个正则表达式(即它还将包含空格),并确保在编写它时它必须匹配的不仅仅是数字。
类似于:
CHAR: /[^-:#()\[\]{}\n]/
CHAR_ND: /[^-:#()\[\]{}\n\d]/
STRING: CHAR_ND CHAR* | CHAR* CHAR_ND
我正在为类似 YAML 的序列化格式编写语法。我正在使用 LALR 解析器。我在解析标量时遇到了障碍。标量可以是字符串或数字(让我们保持简单,只使用小数或浮点数)。这是我目前所拥有的,我只保留了相关的内容:
pair: pair_key ":" _value
_value: scalar | collection
scalar : (string | number) _NL+
string : WORD+
number : DECIMAL | FLOAT
DECIMAL : /0|[1-9]\d*/i
FLOAT: /((\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i
WORD: /[^-:#()\[\]{}\n\s]+/
// NEWLINE
_NL: /(\r?\n[\t ]*)+/
%import common.WS_INLINE
%ignore WS_INLINE
一个字符串是一个或多个单词。一个 WORD 可以包含任何字符,除了我放在 WORD 正则表达式的否定集中的字符。我希望我的字符串能够包含数字并且仍然被解析为字符串,这就是为什么我的 WORD 否定集中没有数字的原因。问题在于当字符串以这样的数字开头时:
test_strings = """
a : 28 should be parsed as string
b : 28
"""
解析器在看到开头为 28 时无法决定是解析数字还是解析单词。
这是我得到的:
top_map
pair
pair_key
string a
scalar
string
28
should
be
parsed
as
string
pair
pair_key
string b
scalar
string 28
预计:
top_map
pair
pair_key
string a
scalar
string
28
should
be
parsed
as
string
pair
pair_key
string b
scalar
number 28
我该如何解决这个歧义?有没有办法只使用语法来做到这一点?请注意,我不希望我的字符串被引号或其他符号包围以便能够识别它们。
编辑
我已经在我的号码规则中使用更高的优先级解决了这个问题:
string : number WORD+ | WORD+
number.2 : DECIMAL | FLOAT
DECIMAL.2 : /0|[1-9]\d*/i
FLOAT.2: /((\d+\.\d*|\.\d+)(e[-+]?\d+)?|\d+(e[-+]?\d+))/i
WORD: /[^-:#()\[\]{}\n\s]+/
这样,数字将被解析为数字而不是 WORD。以数字开头的字符串后面必须有 WORD。所以在这个修改版本中没有字符串只是一个数字。
在我看来你应该保持语法原样,并在解析完成后将字符串转换为数字(如果有效)。
您仍然可以使用显式 number
规则,它可能会影响解析的上下文,但这里的歧义是可以在事后解决的,这将是最简单的解决方案。
为了完整起见,另一种解决方案是将整个字符串设为单个正则表达式(即它还将包含空格),并确保在编写它时它必须匹配的不仅仅是数字。
类似于:
CHAR: /[^-:#()\[\]{}\n]/
CHAR_ND: /[^-:#()\[\]{}\n\d]/
STRING: CHAR_ND CHAR* | CHAR* CHAR_ND