1

Consider that i have the string,

$string = 'tag2 display="users" limit="5"';

Using the preg_match_all function, i need to get the output

Required o/p

Array
(
    [0] => Array
        (
            [0] => tag2
            [1] => tag2
            [2] => 
        )

    [1] => Array
        (
            [0] => display="users"
            [1] => display
            [2] => users
        )

    [2] => Array
        (
            [0] => limit="5"
            [1] => limit
            [2] => 5
        )

)

I tried using this pattern '/([^=\s]+)="([^"]+)"/' but it is not recognizing the parameter with no value (in this case tag2) Instead it gives the output

What I am getting

Array
(
    [0] => Array
        (
            [0] => display="users"
            [1] => display
            [2] => users
        )

    [1] => Array
        (
            [0] => limit="5"
            [1] => limit
            [2] => 5
        )

)

What will be the pattern for getting the required output ?

EDIT 1: I also need to get the attributes which are not wrapped with quotes ex: attr=val. Sorry for not mentioning before.

Aakash Chakravarthy
  • 10,523
  • 18
  • 61
  • 78

3 Answers3

2

Try this:

<?php

    $string = 'tag2 display="users" limit="5"';
    preg_match_all('/([^=\s]+)(="([^"]+)")?/', $string, $res);

    foreach ($res[0] as $r => $v) {
        $o[] = array($res[0][$r], $res[1][$r], $res[3][$r]);
    }

    print_r($o);

?>

It outputs me:

Array
(
    [0] => Array
        (
            [0] => tag2
            [1] => tag2
            [2] => 
        )

    [1] => Array
        (
            [0] => display="users"
            [1] => display
            [2] => users
        )

    [2] => Array
        (
            [0] => limit="5"
            [1] => limit
            [2] => 5
        )

)
deejayy
  • 760
  • 3
  • 9
1

I think it's not fully possible to give you with one call what you're looking for, but this is pretty close:

$string = 'tag2 display="users" limit=5';
preg_match_all('/([^=\s]+)(?:="?([^"]+)"?|())?/', $string, $res, PREG_SET_ORDER);
print_r($res);

Output:

Array
(
    [0] => Array
        (
            [0] => tag2
            [1] => tag2
            [2] => 
            [3] => 
        )

    [1] => Array
        (
            [0] => display="users"
            [1] => display
            [2] => users
        )

    [2] => Array
        (
            [0] => limit=5
            [1] => limit
            [2] => 5
        )

)

As you can see, the first element has no value, I tried to work around that and offer an empty match now. So this builds the array you were asking for, but has an additional entry on the empty attribute.

However the main point is the PREG_SET_ORDER flag of preg_match_all. Maybe you can live with this output already.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • how to tweak the pattern to get parameters without quotes ? – Aakash Chakravarthy Nov 05 '11 at 10:15
  • @AakashChakravarthy: I added a tweak for those. However, I think if you want something really safe, this needs another update. – hakre Nov 05 '11 at 10:30
  • still more one issue, when the parameter value is empty, the output is not correct... what will be the tweak ? – Aakash Chakravarthy Nov 05 '11 at 10:41
  • Well it's correct, subindex 2 is an empty string. The only thing that differs is that there is an additional subindex 3. Is that really a problem? And leaving a note in case you need to have escape characters in values, this answer is showing some technique: @AakashChakravarthy: I added a tweak for those. However, I think if you want something really safe, this needs another update, see as well http://stackoverflow.com/questions/6243778/split-string-by-delimiter-but-not-if-it-is-escaped/6243797#6243797 – hakre Nov 05 '11 at 10:55
  • no thats not the problem... when `tag param=""` -----> param value is empty, in this case i get a varied o/p. i tried tweaking the `(?:="?([^"]+)"?|())` section, but its in-vain.... do you have any idea ? – Aakash Chakravarthy Nov 05 '11 at 11:01
  • `preg_match_all('/([^\s="]+)(?:="?([^"]*)"?|())?/', $string, $res, PREG_SET_ORDER);` – hakre Nov 05 '11 at 11:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4749/discussion-between-aakash-chakravarthy-and-hakre) – Aakash Chakravarthy Nov 05 '11 at 12:55
  • No, thanks. It's endless. Because once you see that something works, you try something new, and then you see it's broken. Then you come here again and ask for more. Instead you first need to specify what exactly (and completely) you're looking for. Then it's much more safe to get a response you can work with for a longer time. – hakre Nov 05 '11 at 12:56
0

Maybe you're interested in this litte snippet that parses all sorts of attribute styles. <div class="hello" id=foobar style='display:none'> is valid html(5), not pretty, I know…

<?php
$string = '<tag2 display="users" limit="5">';

$attributes = array();
$pattern = "/\s+(?<name>[a-z0-9-]+)=(((?<quotes>['\"])(?<value>.*?)\k<quotes>)|(?<value2>[^'\" ]+))/i";
preg_match_all($pattern, $source, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
  $attributes[$match['name']] = $match['value'] ?: $match['value2'];
}

var_dump($attributes);

will give you

$attributes = array(
  'display' => 'users',
  'limit' => '5',
);
rodneyrehm
  • 13,442
  • 1
  • 40
  • 56