我目前正在熟悉 LPeg 解析器模块。为此,我想将版本字符串(例如11.4
)与list匹配。
这样的列表是一个具有严格语法的字符串,也可以包含范围。这是一个类似 EBNF,但在任何情况下都非常简单的语法(我把它写下来是因为下面的 LPeg 代码可能有点难以阅读):
S = R, { ',', R }
R = N, [ '-', N ]
N = digit+, [ '.', digit+ ]
一个示例字符串是1-9,10.1-11,12
. 这是我的巨大代码:
local L = require "lpeg"
local LV, LP, LC, LR, floor = L.V, L.P, L.C, L.R, math.floor
local version = "7.25"
local function check(a, op, b)
if op and a+0 <= version and version <= b+0 then
return a..op..b -- range
elseif not op and floor(version) == floor(a+0) then
return a -- single item
end
end
local grammar = LP({ "S",
S = LV"R" * (LP"," * LV"R")^0,
R = LV"V" * (LC(LP"-") * LV"V")^-1 / check,
V = LC(LV"D" * (LP"." * LV"D")^-1),
D = (LR("09")^1),
})
function checkversion(str)
return grammar:match(str)
end
所以你会这样称呼它checkversion("1-7,8.1,8.3,9")
,如果当前版本与你应该得到的列表不匹配nil
。
现在,问题是,如果所有调用check
都不返回任何内容(意思是,如果版本不匹配),grammar:match(...)
实际上将没有捕获,因此返回字符串的当前位置。但这正是我不想要的,我想checkversion
返回nil
,或者false
如果没有匹配并且评估结果为 true 的东西,实际上就像string:match
会做的那样。
另一方面,如果我在不匹配的情况下返回或false
返回,我最终会得到来自匹配的返回值,这基本上是无法处理的。nil
check
nil, "1", nil, nil
有任何想法吗?