如何在LPeg模式中更改捕获结果的返回顺序?
2015-6-30 8:6:41
收藏:0
阅读:86
评论:2
假设我有一个模式 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 的 有状态的迭代器函数 只有一个控制变量,并且它必须是迭代器函数返回的第一个值。
在一个允许人们为可变函数的 最后 参数命名的世界中,我可以编写:
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 可以做到。
点赞
用户40691
你可以使用原始解决方案而不使用表捕获或匹配时间捕获,如下所示:
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
2015-12-27 15:56:23
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
匹配时间捕获和上值完成了任务。此函数使用
Cmt确保在将其放入pattern / prepend的捕获前,pos已设置。Cmt = lpeg.Cmt Cp = lpeg.Cp function prepend_final_pos(pattern) -- 上值是动态的,因此此变量属于每次调用 prepend_final_pos 时的新环境。 local pos -- lpeg.Cmt(patt, func) 将整个被搜索的文本传递给 `func` 作为第一个参数,然后传递任何捕获值。忽略第一个参数。 local function setpos(_, x) pos = x -- 如果我们没有返回任何内容,Cmt 将会每次都失败 return true end -- 别让 varargs 受到影响! local function prepend(...) return pos, ... end -- `Cmt(etc etc) / 0` 中的 `/ 0` 是为了摆脱从 setpos 中获取的那个捕获到的 `true`。 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按照预期,实际捕获对新模式返回的位置没有影响;只有原始模式匹配的文本长度才会受到影响。