Namixo
Namixo

Reputation: 11

Convert multidimensional array string to array

There is a built-in function in PHP or something clean for convert multidimensional array string to array?

String like:

['text', 'te\'"x2t', "text", "te\"x'#t", true, True, [false, False, 100, +100], -100, + 10, -   20]

each value can be strings(+ escaped characters), boolean, int(+sign) and array which make it a multidimensional array.

To:

Array
(
    [0] => text
    [1] => te'"x2t
    [2] => text
    [3] => te"x'#t
    [4] => 1
    [5] => 1
    [6] => Array
        (
            [0] => 
            [1] => 
            [2] => 100
            [3] => 100
        )

    [7] => -100
    [8] => 10
    [9] => -20
)

I wrote a regex for this, which make match valid to the string under those statements. So it will not match if the string not follows after the rules.

(?<_ARRAY>\[\s*(?:(?:(?P>VALUE)|(?P>_ARRAY))\s*,\s*)*(?:(?:(?P>VALUE)|(?P>_ARRAY))\s*)\])

Now I want to save the values as they are, without any changes.

It can be done with eval, but far as I know, eval is risky and I wonder if there is a better solution for this.

if (preg_match('/(?<_ARRAY>\[\s*(?:(?:(?P>VALUE)|(?P>_ARRAY))\s*,\s*)*(?:(?:(?P>VALUE)|(?P>_ARRAY))\s*)\])/', $array))
    eval("\$array = $array;");

Upvotes: 1

Views: 202

Answers (1)

Nick
Nick

Reputation: 147146

Update

With a bit of inspiration from this, I've come up with this, which seems to work. Basically the string is split on commas and left and right square brackets that do not occur within quotes, or on single/double quoted strings and each part is processed to turn it into a valid JSON value. The string is then put back together and converted into an array using json_decode:

$str = "['text', 'te\\'\"x,2t', \"tex,t\", \"te\\\"x'#t\", true, True, [false, False, 100, +100], -100, + 10, -   20]";
$parts = preg_split('/\s*("(?:\\\\"|[^"])*"|\'(?:\\\\\'|[^\'])*\')\s*|\s*([,\[\]])\s*/', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
foreach ($parts as &$part) {
    if (preg_match("/^'(.*)'/", $part, $matches)) {
        $part = '"' . str_replace(array('"', "\\'"), array('\\"', "'"), $matches[1]) . '"';
        continue;
    }
    $lpart = strtolower($part);
    if ($lpart == 'true' || $lpart == 'false') {
        $part = $lpart;
        continue;
    }
    if (preg_match('/^\+\s*(\d+)$/', $part, $matches)) {
        $part = $matches[1];
        continue;
    }
    if (preg_match('/^-\s*(\d+)$/', $part, $matches)) {
        $part = '-' . $matches[1];
        continue;
    }
}
$json = implode('', $parts);
var_dump(json_decode($json));

Output:

array(10) {
  [0]=>
  string(4) "text"
  [1]=>
  string(8) "te'"x,2t"
  [2]=>
  string(5) "tex,t"
  [3]=>
  string(7) "te"x'#t"
  [4]=>
  bool(true)
  [5]=>
  bool(true)
  [6]=>
  array(4) {
    [0]=>
    bool(false)
    [1]=>
    bool(false)
    [2]=>
    int(100)
    [3]=>
    int(100)
  }
  [7]=>
  int(-100)
  [8]=>
  int(10)
  [9]=>
  int(-20)
}

Demo on 3v4l.org

Original Answer

If you convert all the single quotes to double quotes, the string is valid JSON and can be decoded using json_decode:

$str = "['text', 'text', 100, ['text', false], false, ['text', 200], 'text']";
$json = str_replace("'", '"', $str);
print_r(json_decode($json));

Output:

Array
(
    [0] => text
    [1] => text
    [2] => 100
    [3] => Array
        (
            [0] => text
            [1] => 
        )    
    [4] => 
    [5] => Array
        (
            [0] => text
            [1] => 200
        )    
    [6] => text
)

Demo on 3v4l.org

Upvotes: 1

Related Questions