add tag
David (imported from SE)
There must be a fast and efficient way to split a (text) string at the "nth" occurrence of a needle, but I cannot find it. There is a fairly full set of functions in the [strpos comments in the PHP manual](http://www.php.net/manual/en/function.strpos.php#102336), but that seems a bit much for what I need.

I have plain text as `$string`, and want to split it at *nth* occurrence of `$needle`, and in my case, `needle` is simply a space. (I can do the sanity checks!)

Can someone point me in the right direction? Many thanks!
Top Answer
Galled (imported from SE)
Could be?

    function split2($string,$needle,$nth){
    $max = strlen($string);
    $n = 0;
    for($i=0;$i<$max;$i++){
    	if($string[$i]==$needle){
    		$n++;
    		if($n>=$nth){
    			break;
    		}
    	}
    }
    $arr[] = substr($string,0,$i);
    $arr[] = substr($string,$i+1,$max);
    
    return $arr;
    }
Answer #2
Jack Douglas
You can use recursion to do this too:

```
function strposn(string $haystack, string $needle, $nth, $offset = 0){ return $nth?strposn($haystack,$needle,$nth-1,strpos($haystack,$needle,$offset)+1):$offset; }

$my_string = 'one two three four five six';
$split_pos = strposn($my_string,' ',4);
echo 'left: "'.substr($my_string,0,$split_pos-1).'"'.PHP_EOL;
echo 'right: "'.substr($my_string,$split_pos).'"'.PHP_EOL;
```

produces:

```none
left: "one two three four"
right: "five six"
```

If you care what happens when passing in either 0 or a number higher than the actual number of occurrences you may need to add some checking.
Answer #3
Vardkin (imported from SE)
I really like Hamze GhaemPanah's [answer][1] for its brevity. However, there's a small bug in it. 

In the original code:
```
$i = $pos = 0;    
do {
        $pos = strpos( $string, $needle, $pos+1 );
} while( $i++ < $nth);
```

`$nth` in the `do while` loop should be replaced with `($nth-1)` as it will incorrectly iterate one extra time - setting the `$pos` to the position of the `$nth+1` instance of the needle. Here's an example [playground to demonstrate][2]. If this link fails here is the code:

```
$nth = 2;
$string = "44 E conway ave west horse";
$needle = " ";

echo"======= ORIGINAL =======\n";

$i = $pos = 0;    
do {
        $pos = strpos( $string, $needle, $pos+1 );
} while( $i++ < $nth);

echo "position: $pos \n";
echo substr($string, 0, $pos) . "\n\n";

/* 
    Outputs:

    ======= ORIGINAL =======
    position: 11 
    44 E conway
*/

echo"======= FIXED =======\n";

$i = $pos = 0;    
do {
    $pos = strpos( $string, $needle, $pos+1 );
} while( $i++ < ($nth-1) );

echo "position: $pos \n";
echo substr($string, 0, $pos);

/*
    Outputs:

    ======= FIXED =======
    position: 4 
    44 E

*/
```

That is, when searching for the position of the 2nd instance of our needle, our loop iterates one extra time setting `$pos` to the position of our 3rd instance of our needle. So, when we split the string on the 2nd instance of our needle - as the OP asked - we get the incorrect substring.

Kudos to Hamze for the clever answer.

  [1]: /php?q=1071#a1290
  [2]: https://www.tehplayground.com/vAutCoJvXvqRBWAu
Answer #4
Hamze GhaemPanah (imported from SE)
Easily, just do it: (updated!)

    $i = $pos = 0;    
    do {
            $pos = strpos( $string, $needle, $pos+1 );
    } while( ++$i < $nth);
Answer #5
John (imported from SE)
If your needle will always be 1 character, use Galled's answer, it's going to be faster by quite a bit.  If your $needle is a string, try this.  Seems to work fine.

	function splitn($string, $needle, $offset)
	{
		$newString = $string;
		$totalPos = 0;
		$length = strlen($needle);
		for($i = 0; $i < $offset; $i++)
		{
			$pos = strpos($newString, $needle);
	
			// If you run out of string before you find all your needles
			if($pos === false)
				return false;
			$newString = substr($newString, $pos+$length);
			$totalPos += $pos+$length;
		}
		return array(substr($string, 0, $totalPos-$length),substr($string, $totalPos));
	}
Answer #6
LWC (imported from SE)
Taking [Matthew's answer][1] and adding a solution for [Dɑvïd's comment][2]:

    function split_nth($str, $delim, $n) {
      $result = array_map(function($p) use ($delim) {
          return implode($delim, $p);
      }, array_chunk(explode($delim, $str), $n));
      $result_before_split = array_shift($result);
      $result_after_split = implode(" ", $result); 
      return array($result_before_split, $result_after_split);
    }

Just call it by:

    list($split_before, $split_after) = split_nth("1 2 3 4 5 6", " ", 2);

Output:

    1 2
    3 4 5 6


  [1]: https://stackoverflow.com/a/5956463/4829915
  [2]: https://stackoverflow.com/questions/5956066/how-to-split-a-string-in-php-at-nth-occurrence-of-needle/5956463#comment6869588_5956463

This room is for discussion about this question.

Once logged in you can direct comments to any contributor here.

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.