2013-02-15 20 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