首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在LPeg模式中更改捕获的返回顺序?

在LPeg模式中更改捕获的返回顺序?
EN

Stack Overflow用户
提问于 2015-06-30 08:06:40
回答 2查看 138关注 0票数 1

(我使用Lua5.2和LPeg 0.12)

假设我有一个模式P,它产生一些不确定的捕获数(如果有的话),并且我想要编写create模式Q来捕获P以及在P之后的位置--但是在捕获P之前返回这个位置。本质上,如果lpeg.match(P * lpeg.Cp(), str, i)导致了v1, v2, ..., j,那么我希望lpeg.match(Q, str, i)产生j, v1, v2, ...

这是否可以实现,而不必每次匹配P时都创建一个新表?

大多数情况下,我想这样做是为了简化一些产生迭代器的函数。Lua的无状态迭代器函数只获得一个控制变量,它需要是迭代器函数返回的第一个值。

在一个允许人们将变量函数的最后一个参数命名的世界中,我可以这样写道:

代码语言:javascript
复制
function pos_then_captures(pattern)
    local function roll(..., pos)
        return pos, (...)
    end
    return (pattern * lpeg.Cp()) / roll
end

天哪。简单的解决办法是明智地使用lpeg.Ct()

代码语言:javascript
复制
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可以做一些事情。

EN

回答 2

Stack Overflow用户

发布于 2015-07-02 02:34:05

匹配时间捕获和向上值完成工作。该函数使用Cmt来确保在将pos放在patternpattern / prepend中捕获之前设置好。

代码语言:javascript
复制
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

抽样会议:

代码语言:javascript
复制
> 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
EN

Stack Overflow用户

发布于 2015-12-27 15:56:23

您可以使用原始解决方案w/o表捕获或匹配时间捕获这样的方法来完成此操作。

代码语言:javascript
复制
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‘,其前面是匹配的结尾。

代码语言:javascript
复制
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
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31132828

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档