現在、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
はそうします。
一方、不一致の場合に returnfalse
またはnil
fromの場合、基本的に処理できないcheck
match like からの戻り値になります。nil, "1", nil, nil
何か案は?