我很难理解\G
锚在 PHP 风格的正则表达式中是如何工作的。
我倾向于认为(即使我可能错了),\G
而不是^
在发生相同字符串的多个匹配的情况下使用它。
有人可以举一个\G
应该如何使用的例子,并解释它是如何工作的以及为什么工作吗?
更新
\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 断言才为真,如 preg_match() 的 offset 参数所指定。当 offset 的值非零时,它与 \A 不同。
http://www.php.net/manual/en/regexp.reference.escape.php
您将不得不向下滚动该页面,但它确实存在。
ruby 中有一个非常好的例子,但在 php 中也是一样的。
\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~
该字符串由以下各项组成:
\
and '
,并且保留空格。可以使用单引号字符串指定空字符串。\
or '
。为了简单起见,让我们假设输入不包含换行(在实际情况下,您需要考虑它)。它会增加正则表达式的复杂性,而不会证明这一点。
单引号字符串'(?:[^\\']|\\[\\'])*+'
的 RAW 正则表达式是 未引用字符串的 RAW 正则表达式是[^\s'\\]++
你不需要太在意上面的 2 段正则表达式。
下面的解决方案\G
可以确保当引擎找不到任何匹配时,从字符串开头到最后一个匹配位置的所有字符都已被消耗掉。由于它不能跳过字符,因此引擎将在无法找到两种标记规范的有效匹配时停止匹配,而不是在字符串的其余部分中抓取随机内容。
建造
在构建的第一步,我们可以把这个正则表达式放在一起:
\G(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
或者简单地说(这不是正则表达式 - 只是为了更容易阅读):
\G(Singly_quote_regex|Unquoted_regex)
这将只匹配第一个标记,因为当它第二次尝试匹配时,匹配会在之前的空格处停止'some input...
。
我们只需要添加一点,以允许 0 或更多空间,以便在随后的匹配中,消耗上次匹配留下的位置的空间:
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++))
上面的正则表达式现在将正确识别标记,如此处所示。
可以进一步修改正则表达式,以便在引擎无法检索任何有效令牌时返回字符串的其余部分:
\G *+(?:'((?:[^\\']|\\[\\'])*+)'|([^\s'\\]++)|((?s).+$))
由于按从左到右的顺序尝试交替,((?s).+$)
当且仅当前面的字符串不构成有效的单引号或不带引号的标记时,最后一个选项才会匹配。这可用于检查错误。
第一个捕获组将包含单引号字符串中的文本,需要额外处理才能转换为所需的文本(这里并不相关,所以我把它留给读者作为练习)。第二个捕获组将包含未加引号的字符串。第三个捕获组充当输入字符串无效的指示符。
结论
上面的示例演示了\G
in 标记化的一种使用场景。可能还有其他我没有遇到过的用法。