正则表达式中'\ G'锚点的用途是什么?

Dim*_*zov 8 php regex

我很难理解\G锚如何在正则表达式的PHP风格中起作用.

我倾向于认为(即使我可能错了),\G而不是^在相同字符串的多个匹配发生的情况下使用.

有人可以展示一个\G应该如何使用的例子,并解释它是如何以及为什么有效的?

Jro*_*rod 9

UPDATE

\ G强制模式仅返回作为连续匹配链的一部分的匹配.从第一场比赛开始,每场后续比赛必须先进行比赛.如果你打破链条,比赛结束.

<?php
$pattern = '#(match),#';
$subject = "match,match,match,match,not-match,match";

preg_match_all( $pattern, $subject, $matches );

//Will output match 5 times because it skips over not-match
foreach ( $matches[1] as $match ) {
    echo $match . '<br />';
}

echo '<br />';

$pattern = '#(\Gmatch),#';
$subject = "match,match,match,match,not-match,match";

preg_match_all( $pattern, $subject, $matches );

//Will only output match 4 times because at not-match the chain is broken
foreach ( $matches[1] as $match ) {
    echo $match . '<br />';
}
?>
Run Code Online (Sandbox Code Playgroud)

这直接来自文档

反斜杠的第四个用法是用于某些简单的断言.断言指定必须在匹配中的特定点处满足的条件,而不消耗主题字符串中的任何字符.下面描述了使用子模式进行更复杂的断言.反向断言是

 \G
    first matching position in subject
Run Code Online (Sandbox Code Playgroud)

仅当当前匹配位置位于匹配的起始点时,\ G断言才为真,如preg_match()的偏移参数所指定.当offset的值不为零时,它与\ A不同.

http://www.php.net/manual/en/regexp.reference.escape.php

您将不得不向下滚动该页面,但它确实存在.

在ruby中有一个非常好的例子,但它在php中是相同的.

Anchor\z和\ G如何在Ruby中运行?


nha*_*tdh 6

\G 将匹配匹配边界,该边界要么是字符串的开头,要么是消耗最后匹配的最后一个字符的点。

当您需要进行复杂的令牌化时,同时还要确保令牌有效时,它特别有用。

示例问题

让我们以标记此输入为例:

input 'some input in quote' more input   '\'escaped quote\''   lots@_$of_fun    ' \' \\  ' crazy'stuff'
Run Code Online (Sandbox Code Playgroud)

放入这些标记(我~用来表示字符串的结尾):

input~
some input in quote~
more~
input~
'escaped quote'~
lots@_$of_fun~
 ' \  ~
crazy~
stuff~
Run Code Online (Sandbox Code Playgroud)

该字符串由以下各项组成:

  • 用单引号引起来的字符串,它允许对\和进行转义,并且'保留空格。可以使用单引号字符串指定空字符串。
  • 或无引号的字符串,它由一系列非空格字符组成,并且不包含\'
  • 2个未加引号的字符串之间的空格将分隔它们。不需要空格来分隔其他情况。

为了简单起见,让我们假设输入不包含换行符(实际上,您需要考虑换行符)。这将增加正则表达式的复杂性,而无需说明这一点。

但是,单引号字符串的RAW正则表达式为,'(?:[^\\']|\\[\\'])*+'
而单引号字符串的RAW正则表达式为。[^\s'\\]++
您不必太在意上面的2个正则表达式。

下面的解决方案\G可以确保当引擎无法找到任何匹配项时,从字符串开头到最后一个匹配项的所有字符都将被消耗。由于无法跳过字符,因此当引擎无法找到两种令牌规格的有效匹配项时,引擎将停止匹配,而不是在字符串的其余部分中获取随机内容。

施工

在构建的第一步,我们可以将以下正则表达式放在一起:

\G(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
Run Code Online (Sandbox Code Playgroud)

或简单地说(这不是正则表达式-只是为了使其更易于阅读):

\G(Singly_quote_regex|Unquoted_regex)
Run Code Online (Sandbox Code Playgroud)

这将仅匹配第一个令牌,因为当它第二次尝试匹配时,匹配将在之前的空格处停止'some input...


我们只需要添加一点以允许0或更多的空间,以便在随后的匹配中,消耗上一次匹配保留的位置的空间:

\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
Run Code Online (Sandbox Code Playgroud)

正则表达式上面现在将正确地识别标记,比如看到这里


可以对正则表达式进行进一步修改,以便在引擎无法检索任何有效令牌时返回正则表达式的其余部分:

\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++)|((?s).+$))
Run Code Online (Sandbox Code Playgroud)

由于交替是按从左到右的顺序进行的,因此((?s).+$),仅当前面的字符串没有组成有效的单引号或无引号的标记时,最后一种选择才会匹配。这可以用来检查错误。

第一个捕获组将在单引号字符串内包含文本,这需要额外的处理才能转换为所需的文本(此处并不实际相关,因此我将其留给读者练习)。第二个捕获组将包含未引用的字符串。第三捕获组充当输入字符串无效的指示。

最终正则表达式演示

结论

上面的示例演示了\G令牌化中使用的一种情况。可能还有我没有遇到过的其他用法。

  • 我非常感谢您为帮助我理解这件事而付出的所有努力。我真的很感激。 (3认同)
  • @DimitriVorontzov:这更像是接近真实的案例用法,所以它相当复杂。 (2认同)