Должен быть быстрый и эффективный способ разбить строку (текст) на «n-ое» появление иглы, но я не могу ее найти. В комментариях strpos в руководстве PHP имеется довольно полный набор функций, но это немного похоже на то, что мне нужно.
У меня есть текст в виде $string
, и вы хотите разбить его на n-ое вхождение $needle
, а в моем случае needle
– просто пространство. (Я могу сделать проверки здравомыслия!)
Может ли кто-нибудь указать мне в правильном направлении? Большое спасибо!
Может быть?
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; }
Если ваша игла будет всегда иметь 1 символ, используйте ответ Галлида, это будет быстрее. Если ваша игла $ – строка, попробуйте это. Кажется, хорошо работает.
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)); }
Лично я бы просто разделил его на массив с взрывом, а затем взорвал первые n-1
части как первую половину и разложил оставшееся число как вторую половину.
Вот такой подход, который я бы предпочел для решения regexp (см. Мой другой ответ):
function split_nth($str, $delim, $n) { return array_map(function($p) use ($delim) { return implode($delim, $p); }, array_chunk(explode($delim, $str), $n)); }
Просто позвоните по:
split_nth("1 2 3 4 5 6", " ", 2);
Вывод:
array(3) { [0]=> string(3) "1 2" [1]=> string(3) "3 4" [2]=> string(3) "5 6" }
Вы можете использовать что-то вроде следующего:
/* Function copied from the php manual comment you referenced */ function strnripos_generic( $haystack, $needle, $nth, $offset, $insensitive, $reverse ) { // If needle is not a string, it is converted to an integer and applied as the ordinal value of a character. if( ! is_string( $needle ) ) { $needle = chr( (int) $needle ); } // Are the supplied values valid / reasonable? $len = strlen( $needle ); if( 1 > $nth || 0 === $len ) { return false; } if( $insensitive ) { $haystack = strtolower( $haystack ); $needle = strtolower( $needle ); } if( $reverse ) { $haystack = strrev( $haystack ); $needle = strrev( $needle ); } // $offset is incremented in the call to strpos, so make sure that the first // call starts at the right position by initially decreasing $offset by $len. $offset -= $len; do { $offset = strpos( $haystack, $needle, $offset + $len ); } while( --$nth && false !== $offset ); return false === $offset || ! $reverse ? $offset : strlen( $haystack ) - $offset; } // Our split function function mysplit ($haystack, $needle, $nth) { $position = strnripos_generic($haystack, $needle, $nth, 0, false, false); $retval = array(); if ($position !== false) { $retval[0] = substr($haystack, 0, $position-1); $retval[1] = substr($haystack, $position); return $retval; } return false; }
Затем вы просто используете функцию mysplit, вы получите массив с двумя подстроками. Сначала содержит все символы вплоть до n-го вхождения иглы (не входят в комплект), а второй – от n-го появления иглы (входит в комплект) до конца.
Это уродливо, но, похоже, работает:
$foo = '1 2 3 4 5 6 7 8 9 10 11 12 13 14'; $parts = preg_split('!([^ ]* [^ ]* [^ ]*) !', $foo, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); var_dump($parts);
Вывод:
array(5) { [0]=> string(5) "1 2 3" [1]=> string(5) "4 5 6" [2]=> string(5) "7 8 9" [3]=> string(8) "10 11 12" [4]=> string(5) "13 14" }
Замените отдельные пробелы в запросе одним символом, который вы хотите разбить. Это выражение не будет работать как-есть с несколькими символами в качестве разделителя.
Это жестко закодировано для каждого третьего пространства. С небольшой настройкой, возможно, можно легко настроить. Хотя str_repeat
для создания динамического выражения будет работать.
Я отредактировал функцию Галлида, чтобы она взорвалась после каждого n-го вхождения вместо первого.
function split2($string, $needle, $nth) { $max = strlen($string); $n = 0; $arr = array(); //Loop trough each character for ($i = 0; $i < $max; $i++) { //if character == needle if ($string[$i] == $needle) { $n++; //Make a string for every n-th needle if ($n == $nth) { $arr[] = substr($string, $i-$nth, $i); $n=0; //reset n for next $nth } //Include last part of the string if(($i+$nth) >= $max) { $arr[] = substr($string, $i + 1, $max); break; } } } return $arr; }
function strposnth($haystack,$needle,$n){ $offset = 0; for($i=1;$i<=$n;$i++){ $indx = strpos($haystack, $needle, $offset); if($i == $n || $indx === false) return $indx; else { $offset = $indx+1; } } return false; }
function split_nth($haystack,$needle,$nth){ $result = array(); if(substr_count($haystack,$needle) > ($nth-1)){ $haystack = explode($needle,$haystack); $result[] = implode(array_splice($haystack,0,$nth),$needle); $result[] = implode($haystack,$needle); } return $result; }