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

时间:2013-02-15 15:30:18

标签: php regex

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

我倾向于认为(即使我可能错了)在发生同一字符串的多个匹配的情况下使用\G代替^

有人可以举例说明应该如何使用\G,并解释它是如何以及为何起作用的?

2 个答案:

答案 0 :(得分:9)

<强>更新

\ 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 />';
}
?>

这直接来自文档

  

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

 \G
    first matching position in subject
  

\ G断言仅在当前匹配位置为时才为真   匹配的起点,由offset参数指定   的preg_match()。当offset的值不为零时,它与\ A不同。

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

您必须向下滚动该页面,但它就是。

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

How the Anchor \z and \G works in Ruby?

答案 1 :(得分:5)

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

当您需要执行复杂的标记化时,它尤其有用,同时还要确保令牌有效。

示例问题

让我们举例说明这个输入:

input 'some input in quote' more input   '\'escaped quote\''   lots@_$of_fun    ' \' \\  ' crazy'stuff'

进入这些标记(我使用~表示字符串结尾):

input~
some input in quote~
more~
input~
'escaped quote'~
lots@_$of_fun~
 ' \  ~
crazy~
stuff~

该字符串由以下内容组成:

  • 单独引用字符串,允许\'的转义,并且空间是守恒的。可以使用单引号字符串指定空字符串。
  • OR不加引号的字符串,由一系列非空白字符组成,不包含\'
  • 2个未加引号的字符串之间的空格将分隔它们。划定其他案件不需要空间。

为简单起见,我们假设输入不包含新行(在实际情况下,您需要来考虑它)。它会增加正则表达式的复杂性而不会证明这一点。

单引号字符串的RAW正则表达式为'(?:[^\\']|\\[\\'])*+'
并且未加引号的字符串的RAW正则表达式为[^\s'\\]++
不过,你不需要太在意上面的2张正则表达式。

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

<强>建筑

在构建的第一步,我们可以将这个正则表达式组合在一起:

\G(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))

或者简单地说(这是正则表达式 - 只是为了让它更容易阅读):

\G(Singly_quote_regex|Unquoted_regex)

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


我们只需添加一个位以允许0或更多空格,以便在后续匹配中,消耗最后一次匹配所留位置的空间:

\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))

上面的正则表达式现在可以正确识别令牌,如here所示。


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

\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++)|((?s).+$))

由于按从左到右的顺序尝试交替,当且仅当前面的字符串不构成有效的单引号或不引用的标记时,最后一个替代((?s).+$)将匹配。这可用于检查错误。

第一个捕获组将包含单引号字符串中的文本,需要额外的处理才能变成所需的文本(这里没有真正的相关性,所以我把它作为练习留给了读者)。第二个捕获组将包含未加引号的字符串。第三个捕获组充当输入字符串无效的指示符。

Demo for the final regex

<强>结论

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