2016-08-24 109 views
4

假設以下字符串:正則表達式可選重複組

some text here [baz|foo] and here [foo|bar|baz] and even here [option].

我已經成功地得到由這個醜陋的正則表達式(Regex101.com demo)僅匹配:

/(?: 
    \[ 
    (?: 
     \|? 
     ([^\|\[\]]+) 
    )? 
    (?: 
     \|? 
     ([^\|\[\]]+) 
    )? 
    (?: 
     \|? 
     ([^\|\[\]]+) 
    )? 
    \] 
)/ugx 

的一點是,我需要匹配用方括號分組。 所以目前我確實有結果,我需要:

[ 
    { 
    "match": 1, 
    "children": [ 
     { 
     "group": 1, 
     "start": 16, 
     "end": 19, 
     "value": "baz" 
     }, 
     { 
     "group": 2, 
     "start": 20, 
     "end": 23, 
     "value": "foo" 
     } 
    ] 
    }, 
    { 
    "match": 2, 
    "children": [ 
     { 
     "group": 1, 
     "start": 35, 
     "end": 38, 
     "value": "foo" 
     }, 
     { 
     "group": 2, 
     "start": 39, 
     "end": 42, 
     "value": "bar" 
     }, 
     { 
     "group": 3, 
     "start": 43, 
     "end": 46, 
     "value": "baz" 
     } 
    ] 
    }, 
    { 
    "match": 3, 
    "children": [ 
     { 
     "group": 1, 
     "start": 63, 
     "end": 69, 
     "value": "option" 
     } 
    ] 
    } 
] 

結果是正確的,但該正則表達式僅限於在圖案重複的塊數。 是否有一些解決方法使其與sqare托架內的所有選項相匹配?

+2

你可以用拉'preg_replace_callback'然後''爆炸[]'之間的所有值|'。 – chris85

+0

使用PCRE樣式引擎,您只會獲得捕獲組的固定匹配。如果您量化更大組中的捕獲組,則捕獲組如果可以再次匹配則會被覆蓋。這在Dot-Net中不是問題。所以你可以按照chris85提到的方式來完成,或者你可以使用'\ G'構造來挑選括號內的單個值(每個匹配1個)。 – sln

+0

@ chris85當然,可以這樣做。但我想從正則表達式輸出中獲得所有的值。 –

回答

3

由於引擎不會爲您提供這種功能,因此您無法在模式中遞歸地生成捕獲組。這麼說,你有兩個選擇:

  1. 構建基於您輸入的字符串管 |的出現次數正則表達式。

這個你可以建立的([^][|]+)最有可能重複的模式單一的正則表達式,將做一場小組賽的方式,你的願望:

$pattern = (function() use ($string) { 
    $array = []; 
    for ($i = 0; $i <= substr_count($string, "|"); $i++) { 
     $array[] = $i == 0 ? '([^][|]+)' : '([^][|]+)?'; 
    } 
    return implode("\|?", $array); 
})(); 

通過給輸入字符串,如:

some text here [baz] and here [you|him|her|foo|bar|baz|foo|option|test] and even here [another]. 

熟的正則表達式應該是:

~\[([^][|]+)\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?\|?([^][|]+)?]~ 

Live demo

然後你就可以簡單地使用它:

preg_match_all("~\[$pattern]~", $string, $matches, PREG_SET_ORDER); 

Live demo

這是一個解決方法,說明你可以節省時間和避免只建立你的正則表達式頭痛和正則表達式是總是不是一個簡單便捷的解決方案。

  1. 受益於其他語言功能。

上述解決方法並未提供可靠的解決方案。它正在做很多不需要的工作。下面的代碼做適合的工作:

// Capture strings between brackets 
preg_match_all('~\[([^]]+)]~', $string, $matches); 

$groups = []; 

foreach ($matches[1] as $values) { 
    // Explode them on pipe 
    $groups[] = explode('|', $values); 
} 

輸出將是:

Array 
(
    [0] => Array 
     (
      [0] => baz 
     ) 

    [1] => Array 
     (
      [0] => you 
      [1] => him 
      [2] => her 
      [3] => foo 
      [4] => bar 
      [5] => baz 
      [6] => foo 
      [7] => option 
      [8] => test 
     ) 

    [2] => Array 
     (
      [0] => another 
     ) 

) 

Live demo