4

I am trying to split/explode/preg_split a string but I want to keep the delimiter example :

explode('/block/', '/block/2/page/2/block/3/page/4');

Expected result :

array('/block/2/page/2', '/block/3/page/4');

Not sure if I have to loop and then re-prefix the array values or if there is a cleaner way.

I have tried preg_split() with PREG_SPLIT_DELIM_CAPTURE but I get something along the lines of :

array('/block/, 2/page/2', '/block/, 3/page/4');

Which is not what I want. Any help is much appreciated.

nickb
  • 59,313
  • 13
  • 108
  • 143
Purplefish32
  • 647
  • 1
  • 8
  • 24
  • Do you want to do it in one line or just do it? – Aurelio De Rosa Nov 28 '11 at 23:22
  • 1
    possible duplicate of [Is there way to keep delimiter while using php explode or other similar functions?](http://stackoverflow.com/questions/2938137/is-there-way-to-keep-delimiter-while-using-php-explode-or-other-similar-function) – Clive Nov 28 '11 at 23:25
  • I had already read that question, and I dont think it is a duplicate – Purplefish32 Nov 29 '11 at 08:54

3 Answers3

7

You can use preg_match_all like so:

$matches = array();
preg_match_all('/(\/block\/[0-9]+\/page\/[0-9]+)/', '/block/2/page/2/block/3/page/4', $matches);
var_dump( $matches[0]);

Output:

array(2) {
  [0]=>
  string(15) "/block/2/page/2"
  [1]=>
  string(15) "/block/3/page/4"
}

Demo

Edit: This is the best I could do with preg_split.

$array = preg_split('#(/block/)#', '/block/2/page/2/block/3/page/4', -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

$result = array();
for( $i = 0, $count = count( $array); $i < $count; $i += 2)
{
    $result[] = $array[$i] . $array[$i + 1];   
}

It's not worth the overhead to use a regular expression if you still need to loop to prepend the delimiter. Just use explode and prepend the delimiter yourself:

$delimiter = '/block/'; $results = array();
foreach( explode( $delimiter, '/block/2/page/2/block/3/page/4') as $entry)
{
    if( !empty( $entry))
    {
        $results[] = $delimiter . $entry;
    }
}

Demo

Final Edit: Solved! Here is the solution using one regex, preg_split, and PREG_SPLIT_DELIM_CAPTURE

$regex = '#(/block/(?:\w+/?)+(?=/block/))#';
$flags = PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY;
preg_split( $regex, '/block/2/page/2/block/3/page/4', -1, $flags);
preg_split( $regex, '/block/2/page/2/order/title/sort/asc/block/3/page/4', -1, $flags);

Output:

array(2) {
  [0]=>
  string(15) "/block/2/page/2"
  [1]=>
  string(15) "/block/3/page/4"
}
array(2) {
  [0]=>
  string(36) "/block/2/page/2/order/title/sort/asc"
  [1]=>
  string(15) "/block/3/page/4"
}

Final Demo

nickb
  • 59,313
  • 13
  • 108
  • 143
  • Thanks for the reply, the problem in my case is that dont know how many segments exist beforehand, example : explode('/block/', '/block/2/page/2/order/title/sort/asc/block/3/page/4'); expected result : array('/block/2/page/2/order/title/sort/asc', '/block/3/page/4'); – Purplefish32 Nov 29 '11 at 08:48
  • @Purplefish32 - I've added a more detailed answer. Unfortunately I could not achieve the desired results using a single regex and reverted to prepending the delimiter. – nickb Nov 29 '11 at 14:10
  • Perfect, I finally went for the prepend delimiter method, works like a charm thank you to all that have answered – Purplefish32 Nov 29 '11 at 22:07
  • @Purplefish32 - My final edit is the perfect solution, using a single regex and `preg_split` to achieve the desired results exactly. Hope it helps, please let me know! `:)` – nickb Nov 29 '11 at 22:12
1

Keep in mind that:

explode('/block/', '/block/2/page/2/block/3/page/4');

Will result in:

array("", "2/page/2", "3/page/4");

You could use a preg_match_all like

preg_match_all(":(/block/.*?):", $string); // untested

But just prepending the delimiter is a much clearer solution.

Halcyon
  • 57,230
  • 10
  • 89
  • 128
0

Simply use a lookahead. This will match a zero-width position in the string at each point of explosion. To prevent splitting before the first occurrence, use PREG_SPLIT_NO_EMPTY.

Code: (Demo)

$str = '/block/2/page/2/block/3/page/4';

var_export(
    preg_split('~(?=/block/)~', $str, 0, PREG_SPLIT_NO_EMPTY)
);

Output:

array (
  0 => '/block/2/page/2',
  1 => '/block/3/page/4',
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136