Подтвердить что ты не робот

Как разбить строку на PHP при n-ом введении иглы?

Должен быть быстрый и эффективный способ разбить строку (текст) на "n-ое" появление иглы, но я не могу ее найти. Существует довольно полный набор функций в комментариях strpos в руководстве по PHP, но это немного похоже на то, что мне нужно.

У меня есть текст в виде $string, и вы хотите разбить его на n-ое вхождение $needle, а в моем случае needle - просто пробел. (Я могу сделать проверки здравомыслия!)

Может ли кто-нибудь указать мне в правильном направлении? Большое спасибо!

4b9b3361

Ответ 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-й экземпляр нашей иглы - как спросил операционный центр - мы получаем неверную подстроку.

Престижность Хамзе за умный ответ.

Приветствия.