Skyler Blumer
Skyler Blumer

Reputation: 23

Parse string with multidimensional data encapsulated in curly braces

I'm trying to build a recursive function in PHP that takes a string with nested {} values and converts it into an nested array. Is there any built in functions that can simply split this?

Also the { brackets will always be on the same line as the key i.e. (Main{) not Main\n{.

Indentation will also always be consistent.

Example of what I'm looking for below.

  Main{
    NetworkAccess 1; 
    MaxCPE 6; 
    MaxClassifiers 20; 
    GlobalPrivacyEnable 1; 
    BaselinePrivacy{
      AuthTimeout 10; 
      ReAuthTimeout 10; 
      AuthGraceTime 600; 
      OperTimeout 10; 
      ReKeyTimeout 10; 
      TEKGraceTime 600; 
      AuthRejectTimeout 60; 
      SAMapWaitTimeout 1; 
      SAMapMaxRetries 4; 
    }
    UsServiceFlow{
      UsServiceFlowRef 1; 
      QosParamSetType 7; 
      TrafficPriority 2; 
      MaxRateSustained 1000000; 
      SchedulingType 2; 
      MaxTrafficBurst 8000; 
      MaxConcatenatedBurst 8000; 
    }
    DsServiceFlow{
      DsServiceFlowRef 101; 
      QosParamSetType 7; 
      TrafficPriority 2; 
      MaxRateSustained 10000000; 
    }
  }

Desired result:

Array
(
    [Main] => Array
        (
            [NetworkAccess] => 1
            [MaxCPE] => 6
            [MaxClassifiers] => 20
            [GlobalPrivacyEnable] => 1
            [BaselinePrivacy] => Array
                (
                    [AuthTimeout] => 10
                    [ReAuthTimeout] => 10
                    [AuthGraceTime] => 600
                    [OperTimeout] => 10
                    [ReKeyTimeout] => 10
                    [TEKGraceTime] => 600
                    [AuthRejectTimeout] => 60
                    [SAMapWaitTimeout] => 1
                    [SAMapMaxRetries] => 4
                )

            [UsServiceFlow] => Array
                (
                    [UsServiceFlowRef] => 1
                    [QosParamSetType] => 7
                    [TrafficPriority] => 2
                    [MaxRateSustained] => 1000000
                    [SchedulingType] => 2
                    [MaxTrafficBurst] => 8000
                    [MaxConcatenatedBurst] => 8000
                )

            [DsServiceFlow] => Array
                (
                    [DsServiceFlowRef] => 101
                    [QosParamSetType] => 7
                    [TrafficPriority] => 2
                    [MaxRateSustained] => 10000000
                )

        )

)

Upvotes: 1

Views: 138

Answers (2)

The fourth bird
The fourth bird

Reputation: 163362

Another option for your current data and with the consistent curly brackets might be to use a recursive function making use of references keeping track of the current and the parent.

Explode on a newline and pass that array as a starting point. For every iteration take the first one off the top using array_shift which will return null if the array is empty.

If the last character is a {, the current will be the parent and the set a new array as the current for the next iteration.

When the only character is a } use the parent for the next iteration.

For example:

function processItems($items, &$current, &$parent) {
    $item =  trim(array_shift($items));
    if ($item) {

        if (substr($item, -1) === '{') {
            $key = rtrim($item, '{');
            $current[$key] = [];
            processItems($items, $current[$key], $parent);
            return;
        }

        if (trim($item) === '}') {
            processItems($items, $parent, $parent);
            return;
        }

        $parts = explode(' ',  $item);
        $current[$parts[0]] = rtrim($parts[1], ';');

        processItems($items, $current, $parent);
    }
}

$curr = [];
processItems(explode("\n", $data), $curr, $curr);

print_r($curr);

Result

Array
(
    [Main] => Array
        (
            [NetworkAccess] => 1
            [MaxCPE] => 6
            [MaxClassifiers] => 20
            [GlobalPrivacyEnable] => 1
            [BaselinePrivacy] => Array
                (
                    [AuthTimeout] => 10
                    [ReAuthTimeout] => 10
                    [AuthGraceTime] => 600
                    [OperTimeout] => 10
                    [ReKeyTimeout] => 10
                    [TEKGraceTime] => 600
                    [AuthRejectTimeout] => 60
                    [SAMapWaitTimeout] => 1
                    [SAMapMaxRetries] => 4
                )

        )

    [UsServiceFlow] => Array
        (
            [UsServiceFlowRef] => 1
            [QosParamSetType] => 7
            [TrafficPriority] => 2
            [MaxRateSustained] => 1000000
            [SchedulingType] => 2
            [MaxTrafficBurst] => 8000
            [MaxConcatenatedBurst] => 8000
        )

    [DsServiceFlow] => Array
        (
            [DsServiceFlowRef] => 101
            [QosParamSetType] => 7
            [TrafficPriority] => 2
            [MaxRateSustained] => 10000000
        )

)

Php demo

Upvotes: 0

AbraCadaver
AbraCadaver

Reputation: 78994

JSON would be better, but it was going to be more difficult as it doesn't like trailing commas where they are not needed (PHP doesn't mind).

$string = "[".str_replace(['{', '}', ';'], ['[', '],', ','], $string)."]";
$string =  preg_replace('/([a-z]+)/i', '"$1" =>', $string);
eval("\$result = $string;");
print_r($result);

Upvotes: 2

Related Questions