【问题标题】:Using lpeg to only capture on word boundaries使用 lpeg 仅捕获单词边界
【发布时间】:2016-12-06 01:16:08
【问题描述】:

我一直致力于使用 LPEG 实现语法高亮支持的 a text editor。启动和运行非常简单,但我只完成了最低要求。

我已经定义了一堆这样的模式:

 -- Keywords
 local keyword = C(
    P"auto" +
    P"break" +
    P"case" +
    P"char" + 
    P"int" 
    -- more ..
  ) / function() add_syntax( RED, ... )

这可以正确处理输入,但不幸的是匹配太多。例如,int 匹配 printf 的中间部分,这是意料之中的,因为我使用“P”进行文字匹配。

显然要执行“正确”突出显示,我需要匹配单词边界,例如“int”匹配“int”,但不匹配“printf”、“vsprintf”等。

我试图用它来限制匹配只发生在“<[{ \n”之后,但这并没有达到我想要的效果:

  -- space, newline, comma, brackets followed by the keyword
  S(" \n(<{,")^1 * P"auto"  + 

我在这里是否缺少一个简单、明显的解决方案来仅匹配由空格或其他您在 C 代码中期望的字符包围的关键字/标记?我确实需要捕获的令牌,以便我可以突出显示它,但除此之外,我不会接受任何特定的方法。

例如这些应该匹配:

 int foo;
 void(int argc,std::list<int,int> ) { .. };

但这不应该:

 fprintf(stderr, "blah.  patterns are hard\n");

【问题讨论】:

    标签: parsing lua lpeg


    【解决方案1】:

    LPeg 构造 -pattern(或者更具体地说是以下示例中的 -idchar)可以很好地确保 pattern(即 @987654324)不跟随当前匹配@)。幸运的是,这也适用于输入末尾的空字符串,因此我们不需要对此进行特殊处理。为了确保匹配前面没有模式,LPeg 提供了lpeg.B(pattern)。不幸的是,这需要一个匹配固定长度字符串的模式,因此在输入的开头不起作用。为了解决这个问题,以下代码分别尝试在输入的开头不匹配 lpeg.B(),然后返回到检查字符串其余部分的后缀 前缀的模式:

    local L = require( "lpeg" )
    
    local function decorate( word )
      -- highlighting in UNIX terminals
      return "\27[32;1m"..word.."\27[0m"
    end
    
    -- matches characters that may be part of an identifier
    local idchar = L.R( "az", "AZ", "09" ) + L.P"_"
    -- list of keywords to be highlighted
    local keywords = L.C( L.P"in" +
                          L.P"for" )
    
    local function highlight( s )
      local p = L.P{
        (L.V"nosuffix" + "") * (L.V"exactmatch" + 1)^0,
        nosuffix = (keywords / decorate) * -idchar,
        exactmatch = L.B( 1 - idchar ) * L.V"nosuffix",
      }
      return L.match( L.Cs( p ), s )
    end
    
    -- tests:
    print( highlight"" )
    print( highlight"hello world" )
    print( highlight"in 0in int for  xfor for_ |for| in" )
    

    【讨论】:

    • 我要求很高,想要一个盘子里的答案,但你绝对超出了我的预期。公认。非常感谢。
    【解决方案2】:

    我认为您应该否定匹配模式,类似于在documentation 的示例中完成的方式:

    如果我们只想在单词边界处寻找模式,我们可以使用以下转换器:

    local t = lpeg.locale()
    function atwordboundary (p)
      return lpeg.P{
        [1] = p + t.alpha^0 * (1 - t.alpha)^1 * lpeg.V(1)
      }
    end
    

    这个SO answer 也讨论了一些类似的解决方案,所以可能会感兴趣。

    还有another editor component 使用 LPeg 进行语法高亮分析,因此您可能想看看他们如何处理这个问题(或者如果它适用于您的设计,请使用他们的词法分析器)。

    【讨论】:

    • OK 仔细看看这个方法适用于突出显示,但只处理后缀匹配。即“ending”不匹配“end”,但“vend”匹配。
    猜你喜欢
    • 1970-01-01
    • 2021-08-20
    • 2023-02-07
    • 2014-01-16
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 2023-04-02
    • 2016-09-01
    相关资源
    最近更新 更多