JozefVasko
JozefVasko

Reputation: 25

Reverse the order of parenthetically grouped text and reverse the order of parenthetical groups

I have a strings with pattern, something like this:

(X,1,1,3),(X,1,1,3),(X,@2,@2,@2,@2,@2,(Y,1))

And I need to extract from this One big array, reverse order, and generate new string:

(X,(Y,1),@2,@2,@2,@2,@2),(X,3,1,1),(X,3,1,1)

And expected array:

Array (
    [0] => Array(
        [parent] => (X,1,1,3)
        [childs] => Array(
            [0] => X
            [1] => 1
            [2] => 1
            [3] => 3
        )
    [1] => Array(
        [parent] => (X,1,1,3)
        [childs] => Array(
            [0] => X
            [1] => 1
            [2] => 1
            [3] => 3
        )
    [2] => Array(
        [parent] => (X,@2,@2,@2,@2,@2,(Y,1))
        [childs] => Array(
            [0] => X
            [1] => @2
            [2] => @2
            [3] => @2
            [4] => @2
            [5] => @2
            [6] => (Y,1)
        )
)

For now, I have only first level for parents with this code:

   foreach($datasetxml->Solution->Pattern as $el){

        if(substr( $el["Str"], 0, 1 ) === "L"){

            preg_match_all("/\((((?>[^()]+)|(?R))*)\)/", $el["Str"], $text);

            $text = $text[0];

            $text = array_reverse($text);
            
            foreach($text as $t){            
                //$t = str_replace(")", "", $t);
                $new_texts[] = $t;            
            }        
            $new_text = implode(",", $new_texts);        
            $el["Str"] = $new_text;
        }    

    }

Upvotes: 1

Views: 121

Answers (2)

KIKO Software
KIKO Software

Reputation: 16751

I could reverse you pattern by converting it to JSON, then decode and manipulate it. The code looks like this:

<?php

function reverseRecursive($array, $recursing = false) {
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            $array[$key] = '(' . reverseRecursive($value, true) . ')';
        }    
    }
    $first = $recursing ? array_shift($array) . ',' : '';
    return $first . implode(',', array_reverse($array));
}

$data    = '(X,1,1,3),(X,1,1,3),(X,@2,@2,@2,@2,@2,(Y,1))';
$json    = preg_replace(['/[^(),]+/', '/\(/', '/\)/'], 
                        ['"$0"', '[', ']'], "($data)");
$inverse = reverseRecursive(json_decode($json));

echo $inverse;

This results in:

(X,(Y,1),@2,@2,@2,@2,@2),(X,3,1,1),(X,3,1,1)

A demo can be found here: https://3v4l.org/kISpv

preg_replace() is used to turn your pattern into JSON. This is then decoded so it can be processed in PHP. The reverseRecursive() does a basic recursive reverse of the array, leaving the first item in place except for the outer array, and implodes it to a string again.

Upvotes: 1

mickmackusa
mickmackusa

Reputation: 48031

I don't know how well this will hold up on varied input, but it is designed to be recursive in its splitting, reversing, imploding behavior while preserving the first entry's position in each parenthetical group.

The first regex isolates the parent level parenthetical segments and removes the outer parentheses. The second regex isolates the children on the next level. The first child is separated because it is not to be repositioned. Any remaining children are potentially recursively processed, then all children are reversed and appended to the first child. Finally, all parent level segments (with their reversed children) have their order reversed and are re-wrapped with parentheses.

I am fairly confident that this task is going to be too niche to help other developers.

Code: (Demo)

function rSplitReverse($string) {
    preg_match_all("/\(((?:(?>[^()]+)|(?R))*)\)/", $string, $matches);
    foreach ($matches[1] as &$m) {
        if (preg_match_all("/(\((?:(?>[^()]+)|(?R))*\))|[^(),]+/", $m, $items, PREG_SET_ORDER)) {
            $first = array_shift($items)[0];
            foreach ($items as &$item) {
                $item = isset($item[1]) ? rSplitReverse($item[0]) : $item[0];
            }
            $m = "$first," . implode(',', array_reverse($items));
        }
    }
    return '(' . implode('),(', array_reverse($matches[1])) . ')';
}

echo rSplitReverse('(X,1,1,3),(X,1,1,3),(X,@2,@2,@2,@2,@2,(Y,1))');
// (X,(Y,1),@2,@2,@2,@2,@2),(X,3,1,1),(X,3,1,1)

Upvotes: 1

Related Questions