如何在Vim语法文件中定义单行与多行字符串的语法高亮
解决Vim语法高亮中多行字符串与单行字符串的优先级问题
问题背景
你的自定义编程语言字符串规则如下(EBNF):
longstring ::= '"""' {'"'} newline chars newline '"""' {'"'} newline ::= '\n' string ::= '"' chars '"'
其中chars包含字母、数字、下划线、空白符及标点符号;多行字符串以≥3个双引号开头(可附加更多双引号),结束符需与开头双引号数量一致且位于新行,内容为原始字符串无需解析其他语法。
你当前的Vim语法规则:
syn region mylangLongString start=/\z("\{3,}\)\r/ end=/\z1/ contains=@Spell syn region mylangString start=/"/ skip=/\\"/ end=/"/ contains=@mylangSpecial,@Spell hi def link mylangLongString String hi def link mylangString String
出现的问题:单行字符串规则优先匹配双引号,导致多行字符串匹配错误、高亮溢出至后续代码行。
解决方案
1. 调整规则优先级
Vim语法规则遵循先定义的规则优先级更高,因此只需将多行字符串的定义放在单行字符串之前,即可让Vim优先匹配多行字符串。
2. 修正多行字符串匹配正则
你原有的正则存在两个问题:
- 仅匹配
\r作为换行,未兼容通用的\n或\r\n换行格式 - 未确保结束符位于新行的要求
修正后的多行字符串规则:
syn region mylangLongString start=/\z("\{3,})\n/ end=/\n\z1/ keepend contains=NONE
\z("\{3,}):捕获开头的≥3个双引号,用于结尾匹配\n:匹配开头后的换行符(Vim会自动处理\r\n格式的跨平台换行)end=/\n\z1/:匹配内容后的换行,再匹配与开头数量一致的双引号序列keepend:确保结尾的双引号序列不被后续规则(如单行字符串)再次匹配contains=NONE:符合原始字符串要求,不解析内容中的其他语法组
3. 最终完整语法规则
" 先定义多行字符串,确保优先级更高 syn region mylangLongString start=/\z("\{3,})\n/ end=/\n\z1/ keepend contains=NONE " 再定义单行字符串 syn region mylangString start=/"/ skip=/\\"/ end=/"/ contains=@mylangSpecial,@Spell hi def link mylangLongString String hi def link mylangString String
额外说明
- 如果你的编程语言允许开头双引号后有空白字符再换行,可将start正则调整为
/\z("\{3,})\s*\n/,其中\s*匹配任意空白字符(空格、制表符等) - 若需要对多行字符串内容启用拼写检查,可将
contains=NONE改为contains=@Spell
内容的提问来源于stack exchange,提问作者dlroweht
相关产品推荐
相关产品推荐

