我很难理解\G
锚如何在正则表达式的PHP风格中起作用。
我倾向于认为(即使我可能错了)在发生同一字符串的多个匹配的情况下使用\G
代替^
。
有人可以举例说明应该如何使用\G
,并解释它是如何以及为何起作用的?
答案 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中是相同的。
答案 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~
该字符串由以下内容组成:
\
和'
的转义,并且空间是守恒的。可以使用单引号字符串指定空字符串。\
或'
。为简单起见,我们假设输入不包含新行(在实际情况下,您需要来考虑它)。它会增加正则表达式的复杂性而不会证明这一点。
单引号字符串的RAW正则表达式为'(?:[^\\']|\\[\\'])*+'
并且未加引号的字符串的RAW正则表达式为[^\s'\\]++
不过,你不需要太在意上面的2张正则表达式。
下面\G
的解决方案可以确保当引擎找不到任何匹配项时,已经消耗了从字符串开头到最后一次匹配位置的所有字符。由于它无法跳过字符,因此当引擎无法找到两种规格的令牌的有效匹配时,引擎将停止匹配,而不是在字符串的其余部分中抓取随机内容。
<强>建筑强>
在构建的第一步,我们可以将这个正则表达式组合在一起:
\G(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
或者简单地说(这是不正则表达式 - 只是为了让它更容易阅读):
\G(Singly_quote_regex|Unquoted_regex)
这将仅匹配第一个令牌,因为当它第二次尝试匹配时,匹配将在'some input...
之前的空格处停止。
我们只需添加一个位以允许0或更多空格,以便在后续匹配中,消耗最后一次匹配所留位置的空间:
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
上面的正则表达式现在可以正确识别令牌,如here所示。
可以进一步修改正则表达式,以便在引擎无法检索任何有效令牌时返回字符串的其余部分:
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++)|((?s).+$))
由于按从左到右的顺序尝试交替,当且仅当前面的字符串不构成有效的单引号或不引用的标记时,最后一个替代((?s).+$)
将匹配。这可用于检查错误。
第一个捕获组将包含单引号字符串中的文本,需要额外的处理才能变成所需的文本(这里没有真正的相关性,所以我把它作为练习留给了读者)。第二个捕获组将包含未加引号的字符串。第三个捕获组充当输入字符串无效的指示符。
<强>结论强>
以上示例演示了在标记化中使用\G
的一种情况。可能还有其他我没有遇到过的用法。