Search code examples
phpregex

Splitting text into an associative array


Let's say, I have this text:

add name=100YER on-login=":do {:put \"a\";} on-error={};" rate-limit=256k/512k

I want to extract an array with key and value, eg:

{
    "name": "100YER",
    "on-login": ":do {:put \"a\";} on-error={};"
    "rate-limit": "256k/512k"
}

How to do that if there is another value contains a = character?

I used this regex to split it by =, but the problem is in on-login value.

if (preg_match_all('/[^=]+/i', $response, $MATCHES) ){
    //
}

Solution

  • You might use 2 capturing groups with a branch reset group:

    (\w+(?:-\w+)*)=(?|"((?:[^"]+|(?<=\\)")++)"|([^"\s]+))
    

    Explanation

    • ( Capture group 1
      • \w+(?:-\w+)* Match 1+ word chars optionally followed by a - and 1+ word chars
    • ) Close group 1
    • = Match literally
    • (?| Branch reset group
      • "( Match " and start group 2
        • (?:[^"]+|(?<=\\)")++ Match any char except " or \"
      • )" Close group 2 and match "
      • | Or
      • ([^"\s]+) Capture group 3, match any char except " or a whitespace char
    • ) Close branch reset group

    Regex demo | Php demo

    For example

    $re = '/(\w+(?:-\w+)*)=(?|"((?:[^"]+|(?<=\\\\)")++)"|([^"\s]+))/';
    $str = 'add name=100YER on-login=":do {:put \\"a\\";} on-error={};" rate-limit=256k/512k';
    
    preg_match_all($re, $str, $matches);
    $result = array_combine($matches[1], $matches[2]);
    print_r($result);
    

    Output

    Array
    (
        [name] => 100YER
        [on-login] => :do {:put \"a\";} on-error={};
        [rate-limit] => 256k/512k
    )