使用 lpeg 仅捕获单词边界
Using lpeg to only capture on word boundaries
我一直在研究 a text editor,它使用 LPEG 来实现语法高亮支持。准备工作 运行 非常简单,但我只完成了最低要求。
我已经定义了一堆这样的模式:
-- Keywords
local keyword = C(
P"auto" +
P"break" +
P"case" +
P"char" +
P"int"
-- more ..
) / function() add_syntax( RED, ... )
这可以正确处理输入,但遗憾的是匹配太多。例如 int
匹配 printf
中间,这是预期的,因为我使用“P
”进行文字匹配。
显然要执行 "proper" 突出显示我需要在单词边界上进行匹配,这样 "int" 匹配 "int",但不匹配 "printf"、"vsprintf"等
我试图用它来限制匹配只发生在“<[{ \n
”之后,但这并没有达到我想要的效果:
-- space, newline, comma, brackets followed by the keyword
S(" \n(<{,")^1 * P"auto" +
是否有一个我在这里缺少的简单、明显的解决方案来仅匹配被空格或您期望在 C 代码中的其他字符包围的 keywords/tokens?我确实需要捕获的令牌以便突出显示它,但除此之外我没有采用任何特定方法。
例如这些应该匹配:
int foo;
void(int argc,std::list<int,int> ) { .. };
但这不应该:
fprintf(stderr, "blah. patterns are hard\n");
我认为您应该否定匹配模式,类似于 documentation:
示例中的匹配模式
If we want to look for a pattern only at word boundaries, we can use the following transformer:
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 进行语法高亮分析,因此您可能想看看他们是如何处理这个问题的(或者使用他们的词法分析器,如果它适用于您的设计)。
LPeg 构造 -pattern
(或更具体地说,在下面的示例中 -idchar
)可以很好地确保当前匹配未被遵循 pattern
(即 idchar
)。幸运的是,这也适用于输入末尾的空字符串,因此我们不需要对此进行特殊处理。为确保匹配 前面没有 模式,LPeg 提供了 lpeg.B(pattern)
。不幸的是,这需要一个匹配固定长度字符串的模式,因此在输入的开头不起作用。要修复以下代码,在回退到检查字符串其余部分的后缀 和 前缀的模式之前,分别尝试在输入开头不带 lpeg.B()
的情况下进行匹配:
local L = require( "lpeg" )
local function decorate( word )
-- highlighting in UNIX terminals
return "[32;1m"..word.."[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" )
我一直在研究 a text editor,它使用 LPEG 来实现语法高亮支持。准备工作 运行 非常简单,但我只完成了最低要求。
我已经定义了一堆这样的模式:
-- Keywords
local keyword = C(
P"auto" +
P"break" +
P"case" +
P"char" +
P"int"
-- more ..
) / function() add_syntax( RED, ... )
这可以正确处理输入,但遗憾的是匹配太多。例如 int
匹配 printf
中间,这是预期的,因为我使用“P
”进行文字匹配。
显然要执行 "proper" 突出显示我需要在单词边界上进行匹配,这样 "int" 匹配 "int",但不匹配 "printf"、"vsprintf"等
我试图用它来限制匹配只发生在“<[{ \n
”之后,但这并没有达到我想要的效果:
-- space, newline, comma, brackets followed by the keyword
S(" \n(<{,")^1 * P"auto" +
是否有一个我在这里缺少的简单、明显的解决方案来仅匹配被空格或您期望在 C 代码中的其他字符包围的 keywords/tokens?我确实需要捕获的令牌以便突出显示它,但除此之外我没有采用任何特定方法。
例如这些应该匹配:
int foo;
void(int argc,std::list<int,int> ) { .. };
但这不应该:
fprintf(stderr, "blah. patterns are hard\n");
我认为您应该否定匹配模式,类似于 documentation:
示例中的匹配模式If we want to look for a pattern only at word boundaries, we can use the following transformer:
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 进行语法高亮分析,因此您可能想看看他们是如何处理这个问题的(或者使用他们的词法分析器,如果它适用于您的设计)。
LPeg 构造 -pattern
(或更具体地说,在下面的示例中 -idchar
)可以很好地确保当前匹配未被遵循 pattern
(即 idchar
)。幸运的是,这也适用于输入末尾的空字符串,因此我们不需要对此进行特殊处理。为确保匹配 前面没有 模式,LPeg 提供了 lpeg.B(pattern)
。不幸的是,这需要一个匹配固定长度字符串的模式,因此在输入的开头不起作用。要修复以下代码,在回退到检查字符串其余部分的后缀 和 前缀的模式之前,分别尝试在输入开头不带 lpeg.B()
的情况下进行匹配:
local L = require( "lpeg" )
local function decorate( word )
-- highlighting in UNIX terminals
return "[32;1m"..word.."[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" )