(我使用的是Lua 5.2和LPeg 0.12)
假设我有一个模式P
,它会产生一些不确定数量的捕获,如果有的话,我想编写一个模式Q
来捕获P
以及之后的位置P
- 但要在 P
的捕获之前返回的位置。基本上,如果lpeg.match(P * lpeg.Cp(), str, i)
导致v1, v2, ..., j
,那么我希望lpeg.match(Q, str, i)
导致j, v1, v2, ...
。
这是否可以实现,而无需在每次P
匹配时创建新表?
大多数情况下,我想这样做是为了简化一些产生迭代器的函数。 Lua的stateless iterator functions只获得一个控制变量,它必须是迭代器函数返回的第一个值。
在一个让人们为可变参数函数命名 last 参数的世界中,我可以写:
function pos_then_captures(pattern)
local function roll(..., pos)
return pos, (...)
end
return (pattern * lpeg.Cp()) / roll
end
唉。简单的解决方案是明智地使用lpeg.Ct()
:
function pos_then_captures(pattern)
-- exchange the order of two values and unpack the first parameter
local function exch(a, b)
return b, unpack(a)
end
return (lpeg.Ct(pattern) * lpeg.Cp()) / exch
end
或让呼叫者lpeg.match
进行打包/删除/插入/解包舞蹈。正如后者听起来的那样令人讨厌,我可能会这样做,因为lpeg.Ct()
可能会对病态产生一些意想不到的后果,但是"正确的" pos_then_captures
的参数。
每当pattern
成功匹配时,其中任何一个都会创建一个新表格,这在我的应用程序中确实无关紧要,但有没有办法在没有任何打包解压魔法的情况下做到这一点?
我对Lua的内部并不太熟悉,但感觉就像我真正想要做的是从Lua的堆栈中弹出一些东西并将其放回到其他地方,而不是看起来像是一个直接或有效支持的操作,但也许是LPeg在这种特定情况下可以做的事情。
答案 0 :(得分:0)
比赛时间捕获和升值可以完成工作。此功能使用Cmt
确保设置pos
,然后将其pattern
的{{1}}中的pattern / prepend
抓取。{/ p>
Cmt = lpeg.Cmt
Cp = lpeg.Cp
function prepend_final_pos(pattern)
-- Upvalues are dynamic, so this variable belongs to a
-- new environment for each call to prepend_final_pos.
local pos
-- lpeg.Cmt(patt, func) passes the entire text being
-- searched to `function` as the first parameter, then
-- any captures. Ignore the first parameter.
local function setpos(_, x)
pos = x
-- If we return nothing, Cmt will fail every time
return true
end
-- Keep the varargs safe!
local function prepend(...)
return pos, ...
end
-- The `/ 0` in `Cmt(etc etc) / 0` is to get rid of that
-- captured `true` that we picked up from setpos.
return (pattern / prepend) * (Cmt(Cp(), setpos) / 0)
end
示例会话:
> bar = lpeg.C "bar"
> Pbar = prepend_final_pos(bar)
> print(lpeg.match(Pbar, "foobarzok", 4))
7 bar
> foo = lpeg.C "foo" / "zokzokzok"
> Pfoobar = prepend_final_pos(foo * bar)
> print(lpeg.match(Pfoobar, "foobarzok"))
7 zokzokzok bar
按照预期,实际捕获对新模式返回的位置没有影响;只有文本的长度与原始图案匹配。
答案 1 :(得分:0)
您可以使用没有表格捕获的原始解决方案,也可以使用此类匹配时间捕获
function pos_then_captures(pattern)
local function exch(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, ...)
if a1 == nil then return end
if a2 == nil then return a1 end
if a3 == nil then return a2, a1 end
if a4 == nil then return a3, a1, a2 end
if a5 == nil then return a4, a1, a2, a3 end
if a6 == nil then return a5, a1, a2, a3, a4 end
if a7 == nil then return a6, a1, a2, a3, a4, a5 end
if a8 == nil then return a7, a1, a2, a3, a4, a5, a6 end
if a9 == nil then return a8, a1, a2, a3, a4, a5, a6, a7 end
if a10 == nil then return a9, a1, a2, a3, a4, a5, a6, a7, a8 end
local t = { a10, ... }
return t[#t], a1, a2, a3, a4, a5, a6, a7, a8, a9, unpack(t, 1, #t-1)
end
return (pattern * lpeg.Cp()) / exch
end
以下示例使用返回时,每个匹配的'a'与其前面的匹配结尾
local p = lpeg.P{ (pos_then_captures(lpeg.C'a') + 1) * lpeg.V(1) + -1 }
print(p:match('abababcd'))
-- output: 2 a 4 a 6 a