我一直在研究使用LPEG实现语法突出显示支持的a text editor。启动和运行非常简单,但是我仅完成了最低要求。

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

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


这样可以正确处理输入,但不幸的是匹配太多。例如,intprintf中间匹配,这是预期的,因为我在文字匹配中使用“ 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");

最佳答案

LPeg构造-pattern(或更确切地说,在下面的示例中为-idchar)在确保当前匹配项后没有pattern(即idchar)方面做得很好。幸运的是,这也适用于输入末尾的空字符串,因此我们不需要为此进行特殊处理。为了确保匹配之前没有模式,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" )

关于parsing - 使用lpeg仅捕获单词边界,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38690698/

10-09 09:45