必须有一种快速有效的方法在针的“第n”次出现时分割(文本)字符串,但我找不到它。 strpos comments in the PHP manual中有一套相当完整的函数,但这似乎对我需要的内容有所帮助。
我的原始文字为$string
,并希望在 nth 出现$needle
时将其拆分,在我的情况下,needle
只是一个空格。 (我可以做理智检查!)
有人能指出我正确的方向吗?非常感谢!
答案 0 :(得分:19)
可能吗?
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 :(得分:9)
如果您的指针总是1个字符,请使用Galled的答案,它会更快一点。如果你的$ needle是一个字符串,试试这个。似乎工作正常。
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));
}
答案 2 :(得分:8)
就我个人而言,我只是把它拆分成一个爆炸的数组,然后将第一个n-1
部分作为上半部分内爆,并将剩下的数字作为下半部分内爆。
答案 3 :(得分:5)
这是一种我更喜欢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"
}
答案 4 :(得分:1)
您可以使用以下内容:
/* 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次出现(包括)到结尾包含第二次。
答案 5 :(得分:1)
这很难看,但似乎有效:
$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"
}
将查询中的单个空格替换为您要拆分的单个字符。该表达式不能用多个字符作为分隔符。
这是每第3个空间的硬编码。稍微调整一下,可能很容易调整。虽然构建动态表达式的str_repeat
也可以正常工作。
答案 6 :(得分:1)
我编辑了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;
}
答案 7 :(得分:1)
接受Matthew's answer并为Dɑvïd's comment添加解决方案:
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);
}
只需通过以下方式调用它:
list($split_before, $split_after) = split_nth("1 2 3 4 5 6", " ", 2);
输出:
1 2
3 4 5 6
答案 8 :(得分:0)
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;
}
答案 9 :(得分:0)
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;
}
答案 10 :(得分:0)
轻松地做到这一点:
$i = $pos = 0;
do {
$pos = strpos( $string, $needle, $pos+1 );
} while( $i++ < $nth);
答案 11 :(得分:0)
我非常喜欢Hamze GhaemPanah's answer的简洁性。但是,其中有一个小错误。
在原始代码中:
$i = $pos = 0;
do {
$pos = strpos( $string, $needle, $pos+1 );
} while( $i++ < $nth);
$nth
循环中的 do while
应该替换为($nth-1)
,因为它会错误地重复一个额外的时间-将$pos
设置为{{1}的位置}针的实例。这是一个示例playground to demonstrate。如果此链接失败,则代码如下:
$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
*/
迭代到我们的针的第二个实例的位置。因此,当我们在针的第二个实例上拆分字符串时(如OP要求的那样),我们得到了不正确的子字符串。
对Hamze的巧妙回答表示敬意。
干杯。