Regex группа повторного захвата в PHP

0

Я пытаюсь получить информацию из одного файла с помощью маршрутов, поэтому для этой работы я выбрал регулярное выражение, но у меня возникла проблема с повторяющейся информацией, потому что для лучшего вопроса я поставил то, что у меня есть, и что хочу:

Поэтому у меня есть один файл с:

Codes: C - Connected, S - Static, R - RIP, B - BGP,
       O - OSPF IntraArea (IA - InterArea, E - External, N - NSSA)
       A - Aggregate, K - Kernel Remnant, H - Hidden, P - Suppressed,
       U - Unreachable, i - Inactive

O E       0.0.0.0/0           via 10.140, bond1.30, cost 1:10, age 5  
                              via 10.141, bond1.31  
                              via 10.142, bond1.32  
O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  
O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  
O IA      10.138/29       via 10.140, bond1.30, cost 46, age 1029440  
C         10.141/29    is directly connected, bond2.35
C         10.141/29    is directly connected, bond2.35   

И я сделал это регулярное выражение:

(S|R|B|O|A|K|H|P|U|i) +(IA|E|N|) +([0-9.]+)\/([0-9]+) +via +([0-9.]+), +([a-zA-Z0-9.]+|), +cost +([0-9]+:|)([0-9]+), +age +[0-9]+ +\n(( +via +([0-9.]+), +([a-zA-Z0-9.]+|) +\n)+|)

Моя проблема (( +via +([0-9.]+), +([a-zA-Z0-9.]+|) +\n)+|) с конечной частью (( +via +([0-9.]+), +([a-zA-Z0-9.]+|) +\n)+|) потому что это регулярное выражение получает меня это

array[0]=>' via 10.141, bond1.31  
           via 10.142, bond1.32';
array[1]=>'10.142';

array[2]=>'bond1.32';

Но я хочу получить

array[0]=>'10.141';

array[1]=>'bond1.31';

array[3]=>'10.142';

array[4]=>'bond1.32';

Я проверяю регулярное выражение на страницах о регулярном выражении, и один из них говорит мне следующее:

Примечание. Повторная группа захвата будет захватывать только последнюю итерацию. Поместите группу захвата вокруг повторяющейся группы, чтобы захватить все итерации или использовать не захватывающую группу, если вы не заинтересованы в данных

Но я действительно не знаю, что означает это и как это исправить.

Примечание: это для получения файла о маршрутах в cisco с show ip route

ОБНОВЛЕНИЕ 1

Я меняю свое регулярное выражение на

(S|R|B|O|A|K|H|P|U|i) +(IA|E|N|) +([0-9.]+)\/([0-9]+) +via +([0-9.]+), +([a-zA-Z0-9.]+|), +cost +([0-9]+:|)([0-9]+), +age +[0-9]+ +\n(?: +via +([0-9.]+), +([a-zA-Z0-9.]+|) +\n)*

Таким образом, у меня нет

array[0]=>' via 10.141, bond1.31  
       via 10.142, bond1.32';

Но у меня нет повторной части

  • 0
    Вы хотели получить значение для первой части O E ? Сколько via 10.141, bond1.31 может появиться для каждого O E ?
  • 0
    не определено: / может быть ни один, один или несколько
Теги:

2 ответа

1

Хорошо, я изменил ваше регулярное выражение следующим образом:

$txt = "Codes: C - Connected, S - Static, R - RIP, B - BGP,
       O - OSPF IntraArea (IA - InterArea, E - External, N - NSSA)
       A - Aggregate, K - Kernel Remnant, H - Hidden, P - Suppressed,
       U - Unreachable, i - Inactive

O E       0.0.0.0/0           via 10.140, bond1.30, cost 1:10, age 5  
                              via 10.141, bond1.31  
                              via 10.142, bond1.32  
O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  
O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  
O IA      10.138/29       via 10.140, bond1.30, cost 46, age 1029440  
C         10.141/29    is directly connected, bond2.35
C         10.141/29    is directly connected, bond2.35   
";

$regexp = '#(.) +([A-Z]{1,2}) +([\d.]+/\d+) +via ([\d.]+), ([a-zA-Z0-9.]+), cost [\d:]+, age \d+ +(?:\n +via ([\d.]+), ([a-zA-Z0-9.]+))*#m';
$matches = [];
preg_match_all($regexp, $txt, $matches, PREG_SET_ORDER);
var_dump($matches);

Это выводится:

array(4) {
  [0] =>
  array(8) {
    [0] =>
    string(125) "O E       0.0.0.0/0           via 10.140, bond1.30, cost 1:10, age 5  
                                  via 10.141, bond1.31"
    [1] =>
    string(1) "O"
    [2] =>
    string(1) "E"
    [3] =>
    string(9) "0.0.0.0/0"
    [4] =>
    string(6) "10.140"
    [5] =>
    string(8) "bond1.30"
    [6] =>
    string(6) "10.141"
    [7] =>
    string(8) "bond1.31"
  }
  [1] =>
  array(6) {
    [0] =>
    string(69) "O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  "
    [1] =>
    string(1) "O"
    [2] =>
    string(1) "E"
    [3] =>
    string(9) "10.112/23"
    [4] =>
    string(6) "10.140"
    [5] =>
    string(8) "bond1.30"
  }
  [2] =>
  array(6) {
    [0] =>
    string(69) "O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  "
    [1] =>
    string(1) "O"
    [2] =>
    string(1) "E"
    [3] =>
    string(9) "10.112/23"
    [4] =>
    string(6) "10.140"
    [5] =>
    string(8) "bond1.30"
  }
  [3] =>
  array(6) {
    [0] =>
    string(70) "O IA      10.138/29       via 10.140, bond1.30, cost 46, age 1029440  "
    [1] =>
    string(1) "O"
    [2] =>
    string(2) "IA"
    [3] =>
    string(9) "10.138/29"
    [4] =>
    string(6) "10.140"
    [5] =>
    string(8) "bond1.30"
  }
}

Это не работает, потому что третий через отсутствует

Новая версия, строка за строкой:

$txt = "Codes: C - Connected, S - Static, R - RIP, B - BGP,
       O - OSPF IntraArea (IA - InterArea, E - External, N - NSSA)
       A - Aggregate, K - Kernel Remnant, H - Hidden, P - Suppressed,
       U - Unreachable, i - Inactive

O E       0.0.0.0/0           via 10.140, bond1.30, cost 1:10, age 5  
                              via 10.141, bond1.31  
                              via 10.142, bond1.32  
O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  
O E       10.112/23       via 10.140, bond1.30, cost 46:1, age 2511  
O IA      10.138/29       via 10.140, bond1.30, cost 46, age 1029440  
C         10.141/29    is directly connected, bond2.35
C         10.141/29    is directly connected, bond2.35   
";

$grouped = [];
$i = 0;
foreach (explode("\n", $txt) as $line) {
    $matches = [];
    if (preg_match('#^(.) +([A-Z]{1,2}) +([\d.]+/\d+) +via ([\d.]+), ([a-zA-Z0-9.]+)#', $line, $matches)) {
        array_shift($matches);
        $grouped[++$i] = $matches;
    } else if(preg_match('#^ +via ([\d.]+), ([a-zA-Z0-9.]+)#', $line, $matches)){
        array_push($grouped[$i], $matches[1], $matches[2]);
    }
}
var_dump($grouped);

Теперь он работает:

array(4) {
  [1] =>
  array(9) {
    [0] =>
    string(1) "O"
    [1] =>
    string(1) "E"
    [2] =>
    string(9) "0.0.0.0/0"
    [3] =>
    string(6) "10.140"
    [4] =>
    string(8) "bond1.30"
    [5] =>
    string(6) "10.141"
    [6] =>
    string(8) "bond1.31"
    [7] =>
    string(6) "10.142"
    [8] =>
    string(8) "bond1.32"
  }
  [2] =>
  array(5) {
    [0] =>
    string(1) "O"
    [1] =>
    string(1) "E"
    [2] =>
    string(9) "10.112/23"
    [3] =>
    string(6) "10.140"
    [4] =>
    string(8) "bond1.30"
  }
  [3] =>
  array(5) {
    [0] =>
    string(1) "O"
    [1] =>
    string(1) "E"
    [2] =>
    string(9) "10.112/23"
    [3] =>
    string(6) "10.140"
    [4] =>
    string(8) "bond1.30"
  }
  [4] =>
  array(5) {
    [0] =>
    string(1) "O"
    [1] =>
    string(2) "IA"
    [2] =>
    string(9) "10.138/29"
    [3] =>
    string(6) "10.140"
    [4] =>
    string(8) "bond1.30"
  }
}
  • 0
    У вас была та же проблема, у вас есть только `[6] => string (6)" 10.141 "[7] => string (8)" bond1.31 "` отсутствует [9] => string(8) "10.142" [10] => string(8) "bond1.32" , но спасибо за ответы
  • 0
    @nicearma Я изменил сценарий.
1

Боюсь, вам нужно будет использовать другое регулярное выражение для получения повторных матчей подшаблонов. Итак, вы можете сделать что-то вроде этого:

preg_match_all("/(?:S|R|B|O|A|K|H|P|U|i) +(?:IA|E|N|) +[0-9.]+\/[0-9]+ +via +([0-9.]+), +([a-zA-Z0-9.]+|), +cost +(?:[0-9]+:|)[0-9]+, +age +[0-9]+ +\n((?: +via +[0-9.]+, +(?:[a-zA-Z0-9.]+|) +\n)*)/",$s,$matches,PREG_SET_ORDER);
foreach($matches as $id=>$match)
{
    unset($matches[$id][0]);
    if(isset($match[3])) {
        preg_match_all("/ +via +([0-9.]+), +([a-zA-Z0-9.]+|) +\n/",$match[3],$subpatternMatches,PREG_SET_ORDER);
        unset($matches[$id][3]);
        foreach($subpatternMatches as $spmid=>$spm) {
                unset($subpatternMatches[$spmid][0]);
                $matches[$id] = array_merge($matches[$id],$subpatternMatches[$spmid]);
        }
    }
}

Который получает следующие данные для вашего файла примера:

array(4) {
  [0]=>
  array(6) {
    [0]=>
    string(6) "10.140"
    [1]=>
    string(8) "bond1.30"
    [2]=>
    string(6) "10.141"
    [3]=>
    string(8) "bond1.31"
    [4]=>
    string(6) "10.142"
    [5]=>
    string(8) "bond1.32"
  }
  [1]=>
  array(2) {
    [1]=>
    string(6) "10.140"
    [2]=>
    string(8) "bond1.30"
  }
  [2]=>
  array(2) {
    [1]=>
    string(6) "10.140"
    [2]=>
    string(8) "bond1.30"
  }
  [3]=>
  array(2) {
    [1]=>
    string(6) "10.140"
    [2]=>
    string(8) "bond1.30"
  }
}
  • 0
    Вроде бы логика, попробую, спасибо, если все будет нормально поставлю ответь

Ещё вопросы

Сообщество Overcoder
Наверх
Меню