2016-08-24 3 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" 
     } 
    ] 
    } 
] 

Результат является правильным, но что регулярное выражение ограничивается количеством повторяющихся блоков в шаблоне. Есть ли способ обхода, чтобы он соответствовал всем параметрам в квадратных скобках?

+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

 Смежные вопросы

  • Нет связанных вопросов^_^