【问题标题】:How to do lookahead properly with LPeg如何使用 LPeg 正确进行前瞻
【发布时间】:2015-01-16 12:46:44
【问题描述】:

要匹配以dog 开头,后跟cat(但不使用cat)的字符串,这样可以:

local lpeg = require 'lpeg'
local str1 = 'dogcat'
local patt1 = lpeg.C(lpeg.P('dog')) * #lpeg.P('cat')
print(lpeg.match(patt1, str1))

输出:dog

要匹配以dog 开头的字符串,然后是任何字符序列,然后是cat(但不使用它),例如正则表达式前瞻(dog.+?)(?=cat),我尝试了这个:

local str2 = 'dog and cat'
local patt2 = lpeg.C(lpeg.P("dog") * lpeg.P(1) ^ 1) * #lpeg.P("cat")
print(lpeg.match(patt2, str2))

我的预期结果是dog and,但它返回nil

如果我丢弃前瞻部分(即使用模式lpeg.C(lpeg.P("dog") * lpeg.P(1) ^ 1)),它可以成功匹配整个字符串。这意味着* lpeg.P(1) ^ 1 部分正确匹配任何字符序列,不是吗?

如何解决?

【问题讨论】:

    标签: lua lpeg


    【解决方案1】:

    您需要在前瞻中可以匹配的每个位置否定“猫”:

    local patt2 = lpeg.C(lpeg.P"dog" * (lpeg.P(1)-lpeg.P"cat") ^ 1) * #lpeg.P"cat"
    

    我认为插入我一直在使用的调试器 (pegdebug) 是合适的,因为它在这种情况下会有所帮助。这是它为原始 lpeg 表达式生成的输出:

    +   Exp 1   "d"
     +  Dog 1   "d"
     =  Dog 1-3 "dog"
     +  Separator   4   " "
     =  Separator   4-11    " and cat"
     +  Cat 12  ""
     -  Cat 12
    -   Exp 1
    

    您可以看到分隔符表达式“吃掉”所有字符,包括“猫”,并且没有任何内容可以匹配 P"cat"

    修改后的表达式的输出如下所示:

    +   Exp 1   "d"
     +  Dog 1   "d"
     =  Dog 1-3 "dog"
     +  Separator   4   " "
     =  Separator   4-8 " and "
     +  Cat 9   "c"
     =  Cat 9-11    "cat"
    =   Exp 1-8 "dog and "
    /   Dog 1   0   
    /   Separator   4   0   
    /   Exp 1   1   "dog and "
    

    这是完整的脚本:

    require 'lpeg'
    local peg = require 'pegdebug'
    local str2 = 'dog and cat'
    local patt2 = lpeg.P(peg.trace { "Exp";
      Exp = lpeg.C(lpeg.V"Dog" * lpeg.V"Separator") * #lpeg.V"Cat";
      Cat = lpeg.P("cat");
      Dog = lpeg.P("dog");
      Separator = (lpeg.P(1) - lpeg.P("cat"))^1;
    })
    print(lpeg.match(patt2, str2))
    

    【讨论】:

    • 太糟糕了,pegdebug 不能与 LPeg.re 一起使用,无需修改 re.lua 的源代码。
    • 可能通过对matchre 中的其他方法进行一些修补来实现。欢迎使用补丁 ;)。
    • 我正在使用 Lpeg.re 的修改版本,对原始版本进行了一些扩展,包括。内置跟踪支持、%1 args、高阶 -> fun'param' 和 %patt'param' 构造,但没有官方存储库来提出这些 PR。修改后的版本非常适合您的pegdebug.lua。这里是a gist you can see a diff 原文。
    • 有趣;我认为应该可以通过对mm.P 访问的一些修补来破解它(根据Grammar 模式中的/ mm.P 的入口点来判断)。
    • 是的,我做了一个相当小的修改——反向引用捕获组T 并调用跟踪函数before 将结果包装在mm.P 中。在 compile 函数中,TG 标志旁边传递,它们已经实现了。
    猜你喜欢
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    • 2018-02-05
    • 1970-01-01
    相关资源
    最近更新 更多