正则表达式 (?!\G) 在语言语法中的作用

What does the regex (?!\G) do in language grammars

我经常在语言语法中看到这个正则表达式,它允许编辑器突出显示语法。

我知道正则表达式试图传达什么:

(?!\G) Negative Lookahead - Assert that it is impossible to match the regex below
\G assert position at the end of the previous match or the start of the string for the first match

下面是引起我注意的片段:

控制台

# console.log(arg1, "arg2", [...])
'begin': '\bconsole\b'
'beginCaptures':
  '0':
    'name': 'entity.name.type.object.console.js'
'end': '(?!\G)'
'patterns': [
  {
    'begin': '\s*(\.)\s*(assert|clear|debug|error|info|log|profile|profileEnd|time|timeEnd|warn)\s*(?=\()'
    'beginCaptures':
      '1':
        'name': 'meta.delimiter.method.period.js'
      '2':
        'name': 'support.function.console.js'
    'end': '(?<=\))'
    'name': 'meta.method-call.js'
    'patterns': [
      {
        'include': '#arguments'
      }
    ]
  }
]

以上代码段来自 atom/language-javascript 包。

根据我浏览各种 text-mate 论坛的理解,为了突出显示,编辑器将从 begin 开始,一直持续到 end 正则表达式。在这里,它首先匹配 console 关键字,然后一直匹配到 end 正则表达式,我无法理解它会在哪里停止?

有人可以解释一下吗?

看一些Language Grammars reference first:

There are two ways a rule can match the document. It can either provide a single regular expression, or two. As with the match key in the first rule above (lines 6-8), everything which matches that regular expression will then get the name specified by that rule. ... The other type of match is the one used by the second rule (lines 9-17). Here two regular expressions are given using the begin and end keys. The name of the rule will be assigned from where the begin pattern matches to where the end pattern matches (including both matches). If there is no match for the end pattern, the end of the document is used.

In this latter form, the rule can have sub-rules which are matched against the part between the begin and end matches.

Note that the regular expressions are matched against only a single line of the document at a time. That means it is not possible to use a pattern that matches multiple lines.

begin, end — these keys allow matches which span several lines and must both be mutually exclusive with the match key. Each is a regular expression pattern. begin is the pattern that starts the block and end is the pattern which ends the block.

您提供的规则匹配 console.log 等文本并突出显示 3 个不同的部分:console.log

'begin': '\bconsole\b'
'beginCaptures':
  '0':
    'name': 'entity.name.type.object.console.js'
'end': '(?!\G)'

在这里,console作为一个完整的单词被匹配,整个匹配(因为第0组是整个匹配)被命名为entity.name.type.object.console.js,然后正则表达式匹配任何字符直到(?!\G) 匹配任何不是最后一次成功匹配的结尾且不是字符串开头的位置。这是让其他嵌套规则起作用所必需的,即那些匹配 '\s*(\.)\s*(assert|clear|debug|error|info|log|profile|profileEnd|time|timeEnd|warn)\s*(?=\()' 模式的规则。否则,该块将在之前完成,并且方法名称将被跳过匹配。