2013-02-15 77 views
5

我很难理解\G anchor如何在PHP风格的正则表达式中工作。正则表达式中' G'锚的用法是什么?

在发生相同字符串的多个匹配的情况下,我倾向于使用\G代替^(尽管我可能错了)。

有人可以请示例\G应该如何使用,并解释如何和为什么它的作品?

+0

请看一个真实的例子这个答案:http://stackoverflow.com/a/2248130/1606729 – koopajah 2013-02-15 15:35:04

+0

@koopajah - 谢谢你。不幸的是,这不是一个恰当的例子。我在问使用\ G锚;您链接的示例使用\ g作为反向引用。 – 2013-02-15 15:38:44

+0

再次感谢@koopajah。新的例子确实使用了\ G,但是从这个例子中,我仍然无法理解任何有关\ G应该如何使用和为什么使用的内容。我唯一看到的是\ G在那里被使用,但为什么它被使用,在其他什么情况下它应该被使用,等等 - 我不明白这一点。请更多的例子? – 2013-02-15 15:42:48

回答

3

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

这是直接从文档

第四使用反斜线的是对于某些简单的断言。一个 断言指定了一个条件,必须在特定的匹配点 处满足条件,而不消耗来自主题 字符串的任何字符。子模式用于更复杂的断言是 下面描述。反斜线的断言是仅在当前匹配位置是 比赛的开始点

\G 
    first matching position in subject 

的\ G断言,是真实的,如通过 的preg_match()的偏移量参数指定。当偏移值不为​​零时,它与\ A不同。

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

你将不得不那一页滚动一点,但它是。

在ruby中有一个很好的例子,但它在php中是一样的。

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

+0

谢谢@Jrod,这对我来说是一个正确的方向,我感谢您发布链接到文档。不幸的是,对于PHP和一般编程来说相对较新,我并没有从文档中掌握文档的实际意义。这就是为什么我要求一个例子。 – 2013-02-15 15:56:53

+0

@DimitriVorontzov我添加了一个简单的例子。我希望这更清楚。 – Jrod 2013-02-15 17:03:09

+0

这真是太棒了,非常感谢你@Jrod! – 2013-02-15 17:06:09

4

\G将匹配匹配的边界,这是字符串的任一开头,或在最后一场比赛的最后一个字符被消耗点。

当您需要执行复杂的标记,同时还要确保标记有效时,它特别有用。

例问题

让我们标记化该输入的例子:

input 'some input in quote' more input '\'escaped quote\'' [email protected]_$of_fun ' \' \\ ' crazy'stuff' 

进入这些令牌(I使用~来表示字符串的结束):

input~ 
some input in quote~ 
more~ 
input~ 
'escaped quote'~ 
[email protected]_$of_fun~ 
' \ ~ 
crazy~ 
stuff~ 

该字符串由以下组合组成:

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

为了简单起见,我们假设输入不包含新线(在现实情况下,你需要考虑)。它会增加正则表达式的复杂性,而不会显示出重点。

为单引号的字符串的RAW正则表达式是'(?:[^\\']|\\[\\'])*+'
而对于未加引号的RAW正则表达式是[^\s'\\]++
你不必太在意了2件以上的正则表达式,虽然。

下面\G该解决方案可以确保当发动机未能找到任何匹配,从字符串到最后一个匹配的位置开始所有字符已被消耗。由于它不能跳过字符,因此当它无法为两个标记的规范找到有效的匹配时,引擎将停止匹配,而不是在字符串的其余部分中抓取随机的东西。

建设

在建设的第一步,我们可以放在一起这个表达式:

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

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

\G(Singly_quote_regex|Unquoted_regex) 

这将仅匹配第一个标记,因为当它尝试在第二次比赛时,比赛在'some input...之前停止。


我们只需要添加一些允许0或更多的空间,因此,在随后的比赛,该位置的剩余空间关闭的最后一场比赛中被消耗:

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

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


正则表达式可以进一步修改,使得它在发动机无法获取任何有效的标记返回字符串的其余部分:

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

由于交替是为了从左到试-right,当且仅当前面的字符串不构成有效的单引号或不引号标记时,最后一个替代((?s).+$)才会匹配。这可以用来检查错误。

第一个捕获组将包含单引号字符内的文本,需要额外的处理变成所需的文本这(它是不是真的与此有关,所以我把它作为一个练习的读者)。第二个捕获组将包含未加引号的字符串。第三个捕获组作为输入字符串无效的指示器。

Demo for the final regex

结论

上面的例子是在标记化的\G使用的一个场景的演示。还有其他的用法我没有遇到过。

+0

谢谢!这个例子非常复杂,让我分析一下。 – 2013-02-15 17:07:24

+1

@DimitriVorontzov:这更像是一种近乎真实的使用情况,所以它非常复杂。 – nhahtdh 2013-02-15 17:13:11

+0

是的,我明白,@ nhahtdh! – 2013-02-15 17:23:57