Изменить порядок текста, сгруппированного в скобках, и изменить порядок групп в скобках

У меня есть строки с шаблоном, примерно так:

(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)

И ожидаемый массив:

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

На данный момент у меня есть только первый уровень для родителей с этим кодом:

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

    }

Регулярные выражения не подходят для обработки подобных вложенных шаблонов.

Barmar 03.06.2024 21:10

Всегда полезно узнать больше о входных данных, кроме того, что они выглядят как «что-то». Это кажется вполне обычным: в начале того, что кажется массивом, есть X или Y, за которыми следуют числа, разделенные запятыми и, возможно, предваряемые знаком @. Наверное, это все имеет какой-то смысл, и, возможно, не будет чего-то типа (X,1,"a,b,c",1,3), но мы не знаем, потому что вы нам не сказали.

KIKO Software 03.06.2024 21:51

В начале стоит X или Y, за которыми следуют цифры, разделенные запятыми и, при необходимости, предваряемые знаком @. Иногда вместо чисел может быть такая группа (Y, 1, 2) — и для этого применяются те же правила. X или Y в начале, за которыми следуют цифры, разделенные запятыми и, возможно, предваряемые знаком @.

JozefVasko 03.06.2024 22:14

Разве вы не хотите анализировать и вложенные уровни?

Olivier 03.06.2024 22:28

в будущем да, но пока это не требуется

JozefVasko 03.06.2024 23:02

Между вашим образцом данных и вашим кодом слишком большой разрыв. if (substr( $el["Str"], 0, 1 ) === "L"){ не имеет никакого смысла с вашими примерными данными.

mickmackusa 04.06.2024 05:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
6
98
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я мог бы перевернуть ваш шаблон, преобразовав его в JSON, а затем декодировав и манипулируя им. Код выглядит следующим образом:

<?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;

Это приводит к:

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

Демо можно найти здесь: https://3v4l.org/kISpv

preg_replace() используется для преобразования вашего шаблона в JSON. Затем он декодируется и может быть обработан в PHP. reverseRecursive() выполняет базовый рекурсивный реверс массива, оставляя первый элемент на месте, за исключением внешнего массива, и снова превращает его в строку.

Я не понимаю, какое отношение к этому имеет ваш «ожидаемый массив», поэтому не знаю, как ответить на эту часть вашего вопроса.

preg_filter() уместно вызывать, когда вы хотите не только очистить символы, но и дисквалифицировать/удалить всю точку данных (функция может использоваться для строки или массива). Если я понимаю ваше намерение кодирования, вы не хотите сокращать подстроку до null, если не удалось найти совпадения. Я считаю, что здесь вам следует использовать preg_replace(). Пожалуйста, поправьте меня, если я ошибаюсь. Соответствующее чтение: preg_replace() и preg_filter()
mickmackusa 04.06.2024 03:24

( и ) в классе символов экранировать не нужно. Первый шаблон не выигрывает от включения в группу захвата. Я рекомендую фигурные скобки на if для соответствия PSR-12. Я мог бы сделать $value модифицируемым по ссылке, но это скорее личный выбор.

mickmackusa 04.06.2024 03:29

@mickmackusa Да, preg_replace() тоже работает и действительно более уместно, изменил это. Я, конечно, не эксперт по регулярным выражениям, я был рад, что это сработало, но чем короче, тем лучше, и фигурные скобки обязательно должны быть там. Для тех, кто хочет увидеть версию ответа, о которой говорит MickMackUSA: нажмите ссылку «отредактировано ...» посередине под ответом, чтобы увидеть ее.

KIKO Software 04.06.2024 08:33

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

Первое регулярное выражение изолирует сегменты в скобках родительского уровня и удаляет внешние круглые скобки. Второе регулярное выражение изолирует детей на следующем уровне. Первый дочерний элемент отделен, поскольку его нельзя перемещать. Любые оставшиеся дочерние элементы потенциально рекурсивно обрабатываются, затем все дочерние элементы меняются местами и добавляются к первому дочернему элементу. Наконец, все сегменты родительского уровня (с их перевернутыми дочерними элементами) имеют обратный порядок и перезаключаются в круглые скобки.

Я вполне уверен, что эта задача будет слишком нишевой, чтобы помочь другим разработчикам.

Код: (Демо)

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)

Мне нравится использовать &$m и &$item в циклах. Это устраняет необходимость наличия ключа.

KIKO Software 04.06.2024 19:35

Другие вопросы по теме