0

In PHP, I need to parse parameters in a string like:

{keyword name1=val1 name2='val2' name3="val3"}

And end up with an array like:

{
  name1 => "val1",
  name2 => "val2",
  name3 => "val3"
}

Each value may or may not be quoted, and can be quoted using either single or double quotes. Also, values may contain spaces, punctuation characters, and even the opposite quote. for example, this could be a valid attribute:

name1="Isn't this OK?"

Ideally, it would also allow escaped quotes inside the value, but that would just be a bonus. I would love to have a function that operates just like the HTML browser parser does when it parses attributes on an HTML tag.

My first thought was to step through the string one character at a time, checking the character following the equal sign to see if it's a quote, then looking for the next matching quote. But that seems tedious and not exactly the most efficient way to parse the string.

The examples I've seen using regex are way over my head, unreadable, and way too complex for me to maintain.

I've also seen examples using DOMdocument, but they do not parse correctly when there is a space or comma inside the value.

I need to do this in PHP, not Javascript.

Is there a function (in PHP) that if I pass it just the attributes portion, it will return the array?

1
  • is name1 name2 regular? Commented May 12, 2015 at 18:50

2 Answers 2

2

I know you said you don't like regex solutions, but i'm going to give you one anyway :) At least people can compare to any other possible answers here not using regex.

You can see, and play around with the regex here: https://regex101.com/r/cT6bT0/1. This will try to explain the regex to you in the upper right corner - titled "Explanation".

Code:

// For demonstration is use heredoc for input string so that i escape of quotes is not necesarry.
$input = <<<END
{keyword name1=val1 name2='val2' name3="val3" name4="Isn't this OK?" name5=okay name6='Isn\'t' name7="A \"quote\""}
END;

$re = "/(?:\\s*(\\w+)\\s*=\\s*(?:'((?:[^'\\\\]|\\\\')*)'|\"((?:[^\"\\\\]|\\\\\")*)\"?|(\\w+)))/"; 

preg_match_all($re, $input, $parts, PREG_SET_ORDER);

$result=[];

foreach ($parts as $part) {
    $result[$part[1]] = stripslashes($part[2] ? $part[2] : ($part[3] ? $part[3] : $part[4])) . "\n";
}

print_r($result);

Output:

Array
(
    [name1] => val1
    [name2] => val2
    [name3] => val3
    [name4] => Isn't this OK?
    [name5] => okay
    [name6] => Isn't
    [name7] => A "quote"
)
Sign up to request clarification or add additional context in comments.

1 Comment

allenmc, that is freaking awesome! Thanks so much!! I may not understand the regex used, but the linked example explained a lot, and eased my fears about maintaining it.
0

Use a function like addslashes() to escape the quotes.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.