0

From a text like:

category=[123,456,789], subcategories, id=579, not_in_category=[111,333]

I need a regex to get something like:

$params[category][0] = 123;
$params[category][1] = 456;
$params[category][2] = 789;
$params[subcategories] = ; // I just need to know that this exists
$params[id] = 579;
$params[not_category][0] = 111;
$params[not_category][1] = 333;

Thanks everyone for the help.

PS

As you suggested, I clarify that the structure and the number of items may change. Basically the structure is:

key=value, key=value, key=value, ...

where value can be:

  • a single value (e.g. category=123 or postID=123 or mykey=myvalue, ...)
  • an "array" (e.g. category=[123,456,789])
  • a "boolean" where the TRUE value is an assumption from the fact that "key" exists in the array (e.g. subcategories)
12
  • where did you get this text? Commented Aug 12, 2013 at 11:06
  • it's the params block of a template engine: {block:Posts category=[123,456,789], subcategories, id=579, not_in_category=[111,333]} Commented Aug 12, 2013 at 11:07
  • What did you try so far? Commented Aug 12, 2013 at 11:08
  • @AldoB Do you need that $params array, or do you just need to know if subcategories is in the list? Commented Aug 12, 2013 at 11:14
  • Lots of attempts, but nothing seems to work.. Commented Aug 12, 2013 at 11:15

4 Answers 4

2

This method should be flexible enough:

$str = 'category=[123,456,789], subcategories, id=579, not_in_category=[111,333]';
$str = preg_replace('#,([^0-9 ])#',', $1',$str); //fix for string format with no spaces (count=10,paginate,body_length=300)
preg_match_all('#(.+?)(,[^0-9]|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $param)
{
    list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
    if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
    {
        $val = explode(',',$match[1]); //turn the comma separated numbers into an array
    }
    $params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
var_dump(isset($params['subcategories']));

Output:

Array
(
    [category] => Array
        (
            [0] => 123
            [1] => 456
            [2] => 789
        )

    [subcategories] => 
    [id] => 579
    [not_in_category] => Array
        (
            [0] => 111
            [1] => 333
        )

)

bool(true) 

Alternate (no string manipulation before process):

$str = 'count=10,paginate,body_length=300,rawr=[1,2,3]';
preg_match_all('#(.+?)(,([^0-9,])|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $k => $param)
{
    list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
    $key = isset($sections[3][$k-1]) ? trim($sections[3][$k-1]).$key : $key; //Fetch first character stolen by previous match
    if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
    {
        $val = explode(',',$match[1]); //turn the comma separated numbers into an array
    }
    $params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';

Another alternate: full re-format of string before process for safety

$str = 'count=10,paginate,body_length=300,rawr=[1, 2,3] , name = mike';
$str = preg_replace(array('#\s+#','#,([^0-9 ])#'),array('',', $1'),$str); //fix for varying string formats
preg_match_all('#(.+?)(,[^0-9]|$)#',$str,$sections); //get each section
$params = array();
foreach($sections[1] as $param)
{
    list($key,$val) = explode('=',$param); //Put either side of the "=" into variables $key and $val
    if(!is_null($val) && preg_match('#\[([0-9,]+)\]#',$val,$match)>0)
    {
        $val = explode(',',$match[1]); //turn the comma separated numbers into an array
    }
    $params[$key] = is_null($val) ? '' : $val;//Use blank string instead of NULL
}
echo '<pre>'.print_r($params,true).'</pre>';
Sign up to request clarification or add additional context in comments.

8 Comments

I was testing out the explode myself when I refreshed the page... you got there earlier! :) GJ!
This solution won't work with a text like this: count=10,paginate,body_length=300 maybe because of the comma right close to param key..
@AldoB You can run $str = preg_replace('#,([^0-9 ])#',', $1',$str); before the process to add spaces after the commas
@AldoB I have another fix if you'd rather not change the string before running the process. Let me know if you want it
@SmokeyPHP I tried to use your last update, but for a string like $str = 'count=10,paginate,body_length=300,rawr=[1, 2,3] , name = mike'; the result is not as expected: Array ( [count] => 10 [paginate] => [body_length] => 300 [rawr] => [1 [2,3]] => [name] => mike ) I'm trying to edit the code, starting from yours will be easier.. thanks..!
|
0

You can use JSON also, it's native in PHP : http://php.net/manual/fr/ref.json.php

It will be more easy ;)

Comments

0
<?php
$subject = "category=[123,456,789], subcategories, id=579, not_in_category=[111,333]";
$pattern = '/category=\[(.*?)\,(.*?)\,(.*?)\]\,\s(subcategories),\sid=(.*?)\,\snot_in_category=\[(.*?)\,(.*?)\]/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);
print_r($matches);
?> 

I think this will get you the matches out... didn't actually test it but it might be a good starting point.

Then you just need to push the matches to the correct place in the array you need. Also test if the subcategories string exists with strcmp or something...

Also, notice that I assumed your subject string has that fixe dtype of structure... if it is changing often, you'll need much more than this...

1 Comment

To get the answer you need, you should try to explain what changes in the structure. For instance, if the # of items in the categories array varies; if the # of items in the not_in_category varies; etc...
0
$str = 'category=[123,456,789], subcategories, id=579, not_in_category=[111,333]';
$main_arr = preg_split('/(,\s)+/', $str);
$params = array();
foreach( $main_arr as $value) {
    $pos = strpos($value, '=');
    if($pos === false) {
        $params[$value] = null;
    } else {
        $index_part = substr($value, 0, $pos);
        $value_part = substr($value, $pos+1, strlen($value));
        $match = preg_match('/\[(.*?)\]/', $value_part,$xarr);
        if($match) {
            $inner_arr = preg_split('/(,)+/', $xarr[1]);
            foreach($inner_arr as $v) {
                $params[$index_part][] = $v;
            }
        } else {
            $params[$index_part] = $value_part;
        }

    }
}

print_r( $params );

Output :

Array
(
    [category] => Array
        (
            [0] => 123
            [1] => 456
            [2] => 789
        )

    [subcategories] => 
    [id] => 579
    [not_in_category] => Array
        (
            [0] => 111
            [1] => 333
        )

)

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.