Search code examples
phparraysregexparsingpreg-match-all

Creating a array based on an expert level string in PHP


I have a string divided based on the answers from this create an array based on a specific string in php. I would like to extend it a bit:

$content = '
    [2130701433] [NAME: aaa] [VALUE: aaa] [EXPIRE: 1 second] [CREATED: Y:m:d H:i:s]
    [2130701433] [NAME: bbb] [VALUE: bbb] [EXPIRE: 2 minute] [CREATED: Y:m:d H:i:s]
    [2130701433] [NAME: ccc] [VALUE: ccc] [EXPIRE: 3 hours] [CREATED: Y:m:d H:i:s]

    [2130701434] [NAME: aaa] [VALUE: aaa] [EXPIRE: 1 second] [CREATED: Y:m:d H:i:s]
    [2130701434] [NAME: bbb] [VALUE: bbb] [EXPIRE: 2 minute] [CREATED: Y:m:d H:i:s]
    [2130701434] [NAME: ccc] [VALUE: ccc] [EXPIRE: 3 hours] [CREATED: Y:m:d H:i:s]

    [2130701435] [NAME: aaa] [VALUE: aaa] [EXPIRE: 1 second] [CREATED: Y:m:d H:i:s]
    [2130701435] [NAME: bbb] [VALUE: bbb] [EXPIRE: 2 minute] [CREATED: Y:m:d H:i:s]
    [2130701435] [NAME: ccc] [VALUE: ccc] [EXPIRE: 3 hours] [CREATED: Y:m:d H:i:s]';

And divide it as follows:

$content = array(
    '2130701433' => array(
        'NAME'      => ['aaa', 'bbb', 'ccc'],
        'VALUE'     => ['aaa', 'bbb', 'ccc'],
        'EXPIRE'    => ['1 second', '2 minute', '3 hours'],
        'CREATED'   => ['Y:m:d H:i:s', 'Y:m:d H:i:s', 'Y:m:d H:i:s']
    ),

    '2130701434' => array(
        'NAME'      => ['aaa', 'bbb', 'ccc'],
        'VALUE'     => ['aaa', 'bbb', 'ccc'],
        'EXPIRE'    => ['1 second', '2 minute', '3 hours'],
        'CREATED'   => ['Y:m:d H:i:s', 'Y:m:d H:i:s', 'Y:m:d H:i:s']
    ),

    '2130701435' => array(
        'NAME'      => ['aaa', 'bbb', 'ccc'],
        'VALUE'     => ['aaa', 'bbb', 'ccc'],
        'EXPIRE'    => ['1 second', '2 minute', '3 hours'],
        'CREATED'   => ['Y:m:d H:i:s', 'Y:m:d H:i:s', 'Y:m:d H:i:s']
    ),
);

Current code:

if(preg_match_all('~\[(\w+):\s*([^][]*)]~', $content, $matches)){
    array_shift($matches);
    array_combine($matches[0], $matches[1]);
}

Is this solution real and is it worth it?

Thank you in advance for your help and I apologize for my English.


Solution

  • The \G "continue" metacharacter is the hero of this pattern. https://www.regular-expressions.info/continue.html This makes the pattern infinitely extensible in case you want to add more bracketed key-value pairs in the future.

    After the id number is found, the pattern seeks a very predictable bracketed structure and doesn't stop matching until the string breaks the continuation pattern.

    Once the $matches array is generated, you only need to isolate which matches are the id numbers. Because the id set of matches doesn't have a [2] element, check for isset($item[2]) -- if it doesn't exist, store the id located at $item[1], otherwise store the key-value pair.

    Code: (Demo) (Regex101 Demo)

    $content = '
        [2130701433] [NAME: aaa] [VALUE: aaa] [EXPIRE: 1 second] [CREATED: Y:m:d H:i:s]
        [2130701433] [NAME: bbb] [VALUE: bbb] [EXPIRE: 2 minute] [CREATED: Y:m:d H:i:s]
        [2130701433] [NAME: ccc] [VALUE: ccc] [EXPIRE: 3 hours] [CREATED: Y:m:d H:i:s]
    
        [2130701434] [NAME: aaa] [VALUE: aaa] [EXPIRE: 1 second] [CREATED: Y:m:d H:i:s]
        [2130701434] [NAME: bbb] [VALUE: bbb] [EXPIRE: 2 minute] [CREATED: Y:m:d H:i:s]
        [2130701434] [NAME: ccc] [VALUE: ccc] [EXPIRE: 3 hours] [CREATED: Y:m:d H:i:s]
    
        [2130701435] [NAME: aaa] [VALUE: aaa] [EXPIRE: 1 second] [CREATED: Y:m:d H:i:s]
        [2130701435] [NAME: bbb] [VALUE: bbb] [EXPIRE: 2 minute] [CREATED: Y:m:d H:i:s]
        [2130701435] [NAME: ccc] [VALUE: ccc] [EXPIRE: 3 hours] [CREATED: Y:m:d H:i:s]';
    
    if(preg_match_all('~\G\s*\[(\d+)]|\s*\[([A-Z]+):\s*(.*?)]~', $content, $matches, PREG_SET_ORDER)){
        //var_export($matches);
        foreach ($matches as $item) {
            if (!isset($item[2])) {
                $id = $item[1];
            } else {
                $result[$id][$item[2]][] = $item[3];
            }
        }
    }
    var_export($result);
    

    Output:

    array (
      2130701433 => 
      array (
        'NAME' => 
        array (
          0 => 'aaa',
          1 => 'bbb',
          2 => 'ccc',
        ),
        'VALUE' => 
        array (
          0 => 'aaa',
          1 => 'bbb',
          2 => 'ccc',
        ),
        'EXPIRE' => 
        array (
          0 => '1 second',
          1 => '2 minute',
          2 => '3 hours',
        ),
        'CREATED' => 
        array (
          0 => 'Y:m:d H:i:s',
          1 => 'Y:m:d H:i:s',
          2 => 'Y:m:d H:i:s',
        ),
      ),
      2130701434 => 
      array (
        'NAME' => 
        array (
          0 => 'aaa',
          1 => 'bbb',
          2 => 'ccc',
        ),
        'VALUE' => 
        array (
          0 => 'aaa',
          1 => 'bbb',
          2 => 'ccc',
        ),
        'EXPIRE' => 
        array (
          0 => '1 second',
          1 => '2 minute',
          2 => '3 hours',
        ),
        'CREATED' => 
        array (
          0 => 'Y:m:d H:i:s',
          1 => 'Y:m:d H:i:s',
          2 => 'Y:m:d H:i:s',
        ),
      ),
      2130701435 => 
      array (
        'NAME' => 
        array (
          0 => 'aaa',
          1 => 'bbb',
          2 => 'ccc',
        ),
        'VALUE' => 
        array (
          0 => 'aaa',
          1 => 'bbb',
          2 => 'ccc',
        ),
        'EXPIRE' => 
        array (
          0 => '1 second',
          1 => '2 minute',
          2 => '3 hours',
        ),
        'CREATED' => 
        array (
          0 => 'Y:m:d H:i:s',
          1 => 'Y:m:d H:i:s',
          2 => 'Y:m:d H:i:s',
        ),
      ),
    )