sybear
sybear

Reputation: 7784

Regex for extracting nested parameters in brackets

I would like to find a proper regexp / recursive algorithm to extract data from a string with brackets.

$input = "0A,0B(1A((3A, 3B, 3C)))";

Expected result:

[ 
  0 => ["0A", "0B"], 
  1 => ["1A"], 
  2 => [], 
  3 => ["3A", "3B", "3C"] 
];

The following function is pretty close, however, it does not detect empty data when there are nested brackets, so the array has size of 3 instead of 4:

function extractParameters($line, &$params, $level = 0){
    $pattern = "/([A-Za-z0-9,:]+)(?:\((.+)?\))?/" ;
    $matches = [] ;

    preg_match($pattern, $line, $matches);

    //We have a valid value
    if (isset($matches[1])){
        $set = $matches[1] ;
        $params[$level] = explode(",", $set);

        //It has some content
        if (isset($matches[2])){
            $content = $matches[2] ;
            extractParameters($content, $params, ++$level);
        }
    }
}

$input = "0A,0B(1A((3A,3B,3C)))" ;
$params = [];
extractParameters($input, $params);
var_dump($params);

Upvotes: 1

Views: 148

Answers (2)

chocochaos
chocochaos

Reputation: 1596

Going by your example, if you change the pattern line to...

$pattern = "/([A-Za-z0-9,:]*)(?:\((.+)?\))?/" ;

...I think it works as you requested.

I switched the plus (+) sign, which makes the pattern require at least one alphanumeric/comma/semicolon character before the parentheses to an asterix (*), so it still matches but is not required.

Upvotes: 2

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627600

Here is a possible solution:

$re = '/(?<=\(|^)([^()]*)/'; 
$str = "0A,0B(1A((3A, 3B, 3C)))"; 
preg_match_all($re, $str, $matches);
$res  = array();
foreach ($matches[1] as $m){
    $res[] = preg_split('/\s*,\s*/',$m);
}
print_r($res);

See IDEONE demo

The regex (?<=\(|^)([^()]*) matches 0 or more characters other than ( or ) if preceded with ( or start of string.

Upvotes: 3

Related Questions