我正在尝试编写一个 GtkSourceView 语言文件来突出显示我在 gedit 中的一些文件。我遇到的问题是我想突出显示至少包含前四个字符且拼写正确的单词。为了说明这一点,假设我有四种模式:
variable
vari
variab
variabel
我想识别前三个,但不是第四个,因为前三个都是目标"变量"的正确拼写子字符串。完成工作的方法是使用
bvari(a|ab|abl|able)?b
但是对于较长的单词,这可能会变得非常乏味。所以在一个完整的 lang 文件中,它看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<language id="foo" _name="foo" version="2.0" _section="Other">
<metadata>
<property name="mimetypes">text/x-foo</property>
<property name="globs">*.foo</property>
</metadata>
<styles>
<style id="keyword" _name="Keyword" map-to="def:keyword"/>
</styles>
<default-regex-options case-sensitive="false"/>
<definitions>
<context id="foo">
<include>
<context id="keyword" style-ref="keyword">
<keyword>bvari(a|ab|abl|able)b</keyword>
</context>
</include>
</context>
</definitions>
</language>
我无法找到解决方案-因为我对正则表达式非常不熟悉,并且不知道这个问题的正确措辞。有没有简单有效的解决方案来解决这个问题?
不幸的是,实际上没有一种不那么乏味的方法可以做到这一点。
关于您的模式:请注意,GtkSourceView
使用 PCRE 正则表达式引擎,该引擎是 NFA 正则表达式引擎。因此,当您编写替代项时,匹配的第一个替代项(从左到右)将成功,并且正则表达式引擎不会在右侧更远处测试其他替代项,例如字符串abcdef
模式(a|ab|abc|abcde|abcdef)
将返回a
(当 DFA 将返回匹配的最长替代项时,所以abcdef
)
这意味着您的模式之所以有效,是因为末尾有一个单词边界(对于整个单词variable
,每个替代项都成功,但是一旦达到单词边界,正则表达式引擎必须回溯并测试下一个替代项,依此类推,直到最后一个。
结论,最好写下从最长的替代方案到最短的替代方案的交替,以避免对引擎进行不必要的工作,因此:
bvari(able|abl|ab|a)?b
另一种可能性是像这样设计你的模式:
bvari(a(b(le?)?)?)?b
在这种情况下,正则表达式引擎直接进入模式的末尾,而不必找到良好的交替。但请注意,它写起来并不简单,而是更短,因为您不必多次写信!