Как разбить строку на PHP при n-ом введении иглы?
Должен быть быстрый и эффективный способ разбить строку (текст) на "n-ое" появление иглы, но я не могу ее найти. Существует довольно полный набор функций в комментариях strpos в руководстве по PHP, но это немного похоже на то, что мне нужно.
У меня есть текст в виде $string
, и вы хотите разбить его на n-ое вхождение $needle
, а в моем случае needle
- просто пробел. (Я могу сделать проверки здравомыслия!)
Может ли кто-нибудь указать мне в правильном направлении? Большое спасибо!
Ответы
Ответ 1
Может быть?
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;
}
Ответ 2
Если ваша игла будет всегда иметь 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));
}
Ответ 3
Лично я бы просто разделил его на массив с взрывом, а затем взорвал первые n-1
части как первую половину, и разложил оставшееся число как вторую половину.
Ответ 4
Вот такой подход, который я бы предпочел для решения 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"
}
Ответ 5
Вы можете использовать что-то вроде следующего:
/* 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-го появления иглы (входит в комплект) до конца.
Ответ 6
Это уродливо, но, похоже, работает:
$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
для построения динамического выражения также будет работать.
Ответ 7
Я отредактировал функцию Galled, чтобы она взорвалась после каждого 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;
}
Ответ 8
Легко, просто сделай это:
$i = $pos = 0;
do {
$pos = strpos( $string, $needle, $pos+1 );
} while( $i++ < $nth);
Ответ 9
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;
}
Ответ 10
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;
}
Ответ 11
Мне очень нравится Hamze GhaemPanah ответ за его краткость. Однако в этом есть небольшая ошибка.
В оригинальном коде:
$i = $pos = 0;
do {
$pos = strpos( $string, $needle, $pos+1 );
} while( $i++ < $nth);
$nth
в цикле do while
следует заменить на ($nth-1)
, так как это приведет к неправильной итерации одного дополнительного времени - установке $pos
в положение экземпляра $nth+1
иглы. Вот пример игровой площадки для демонстрации. Если эта ссылка не работает, вот код:
$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
*/
То есть, при поиске позиции 2-го экземпляра нашей иглы наш цикл повторяет одну дополнительную установку времени $pos
в положение нашего 3-го экземпляра нашей иглы. Таким образом, когда мы разделяем строку на 2-й экземпляр нашей иглы - как спросил операционный центр - мы получаем неверную подстроку.
Престижность Хамзе за умный ответ.
Приветствия.