Regex repeated capturing group in PHP

后端 未结 2 1760
陌清茗
陌清茗 2021-01-26 09:23

i\'m trying to get information from one file with routes, so for this work i chose regex, but i have the problem with the repeted information, for do a better question i will pu

相关标签:
2条回答
  • 2021-01-26 10:03

    Ok I've changed your regexp like this:

    $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);
    

    This is output:

    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"
      }
    }
    

    It does not work because third via is missing

    New version, line by line:

    $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);
    

    Now it is working:

    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 讨论(0)
  • 2021-01-26 10:12

    I'm afraid you'll need to use another regular expression to get the repeated subpattern matches. So, you could do something like this:

    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]);
            }
        }
    }
    

    Which gets the following data for your example file:

    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 讨论(0)
提交回复
热议问题