PHP子字符串提取。获取第一个“/”之前的字符串或整个字符串。

222

我正在尝试提取一个子字符串,在PHP中需要一些帮助。

这里是我正在使用的一些示例字符串和我需要的结果:

home/cat1/subcat2 => home

test/cat2 => test

startpage => startpage

我想获取第一个 / 之前的字符串,但如果没有 /,则获取整个字符串。

我尝试过:

substr($mystring, 0, strpos($mystring, '/'))

我认为它的意思是 - 获取 / 的位置,然后从位置0到那个位置获取子字符串。

如果没有 / 的情况该如何处理,而不使语句过于复杂,我不知道该怎么办。

是否有一种方法可以处理这种情况,而不使PHP语句太复杂?


2
你可能会发现s($str)->beforeFirst('/')很有用,这个函数可以在这个独立库中找到。 - caw
14个回答

408

最高效的解决方案是使用strtok函数:

strtok($mystring, '/')

注意:如果要分割的字符超过一个,则结果可能不符合您的期望,例如strtok("somethingtosplit", "to")返回s,因为它是按照第二个参数中的任何单个字符进行分割(在本例中使用了o)。

@friek108感谢您在评论中指出这一点。

例如:

$mystring = 'home/cat1/subcat2/';
$first = strtok($mystring, '/');
echo $first; // home

$mystring = 'home';
$first = strtok($mystring, '/');
echo $first; // home

33
这相比于当前的“current-explode”解决方案要快大约40%。(虽然我并不经常使用,所以也无关紧要。) - towr
7
这很优雅且快速 - 应该被采纳为答案。 - Kosta Kontos
6
这应该是期望的答案。比任何给出的“explode”解决方案都更快、更节省内存和 CPU 循环效率。 - Shivam Maheshwari
4
在某些情况下这样并不安全,例如尝试使用以下命令:echo strtok("history_table_id","_id"); 它只会返回 "h"。请小心!请注意不要改变原意。 - friek108
1
然而,这取决于用于拆分的字符串是否长于1个字符,处理方式会有所不同。 - Ken
显示剩余3条评论

304

使用 explode()

$arr = explode("/", $string, 2);
$first = $arr[0];

在这种情况下,我使用 limit 参数来使 explode 停止扫描字符串,并且只扫描所需的部分。


3
谢谢回答。它起作用了 :) 但是我有一个问题。我只能这样做-> $arr = explode('/',$mystring,2); echo $arr[0];。我不能在一个语句中得到第一个字符串 - echo explode('/',$mystring,2)[0];。既然explode返回一个数组,我应该可以做到对吗?但是我遇到了错误。有什么建议吗? - anon355079
3
好的,如果可能的话,那就太好了。 - anon355079
40
explode() + [0] is a long-winded way to write strtok($string, "/") - mario
7
顺便提一句,在php 5.5中,你可以使用explode("/", $string, 2)[0]。 - But those new buttons though..
3
使用 strtok() 函数的问题在于,first/second 会返回 first,但 /second 会返回 second 而不是空字符串。 - rybo111
显示剩余4条评论

102
$first = explode("/", $string)[0];

5
优雅,但在计算机时间上不是很高效。但现在人们不再太关心每个CPU周期了。 - Dennis

21

这个怎么样:

substr($mystring.'/', 0, strpos($mystring, '/'))

只需在mystring的末尾添加'/',这样你就可以确保至少有一个分号了 ;)


在执行此操作之前,您可以先检查字符串中是否有一个斜杠。无论如何,这都是最简单的解决方案。 - Guilherme Sampaio

14

迟做总比不做好。PHP有一个预定义函数可以实现这个功能。以下是这种好的方式。

strstr

如果你想要得到匹配之前的部分,只需要将before_needle(第三个参数)设置为true

http://php.net/manual/en/function.strstr.php
function not_strtok($string, $delimiter)
{    
    $buffer = strstr($string, $delimiter, true);

    if (false === $buffer) {
        return $string;
    }

    return $buffer;
}

var_dump(
    not_strtok('st/art/page', '/')
);

2
如果你不能确定针存在于字符串中,这是不安全使用的。 - fooquency
1
@fooquency — 是的,但你可以始终将该字符添加到要检查的字符串末尾,以确保安全。 - MikeSchinkel
1
谢谢。我的测试表明strstrstrtok稍微快一点,我会选择使用前者。 - Ian Y.

13

接受答案的一行版本:

$out=explode("/", $mystring, 2)[0];

应该在PHP 5.4+中工作


1
与下面的代码不同,这里的“2”限制了数组创建的项数。思路很好。 - Ben in CA
我们需要一个新的答案来展示这个被压缩的答案的原因是什么?这不能作为已接受答案的评论或编辑吗? - mickmackusa
@mickmackusa 是的 - 111
"Yes" 是指什么?您认为添加评论或编辑会完成同样的工作吗? - mickmackusa
@mickmackusa 不。 - 111

9

这可能是我想到的最简短的例子:

list($first) = explode("/", $mystring);

1) 如果找到分隔符'/',则list()会自动将字符串赋值给该分隔符之前的部分

2) 如果没有找到分隔符'/',则整个字符串都会被赋值

...如果您对性能真的很着迷,您可以在explode("/", $mystring, 2)中添加额外的参数,以限制返回元素的最大数量。


2
我喜欢这种方法。可以避免创建不必要的数组。而且 strtok() 不安全。 - rybo111
1
@rybo111:strtok()有什么不安全的地方? - hakre
@rybo111 我赞同hakre的观点;strtok()为什么不安全? - Doktor J
1
php 4.1.0 - 真的吗? - hakre
@hakre 如果你的版本 > 4.1.0(我希望是这样),那么行为可能不会如你所预期,因为它会跳过空令牌。 - rybo111
显示剩余4条评论

6
你可以尝试使用这样的正则表达式:

$s = preg_replace('|/.*$|', '', $s);

有时,正则表达式的速度可能会较慢。因此,如果性能是一个问题,请确保正确地进行基准测试,并使用其他适合您的子字符串替代方案。


2
正则表达式可能也有点过头了,但既然我对“explode”也是这么说的,看看哪个更快可能会很有趣。 - rvighne
1
这段代码没有任何问题,我想不出它为什么应该被踩两次。我个人不会使用正则表达式,但它肯定是正确的。 - But those new buttons though..

5

PHP 5.3中的函数strstr()可以完成此任务。但第三个参数应设置为true。

但如果您不使用5.3,则下面的函数应该可以准确工作:

function strbstr( $str, $char, $start=0 ){
    if ( isset($str[ $start ]) && $str[$start]!=$char ){
        return $str[$start].strbstr( $str, $char, $start+1 );
    }
}

虽然我没有测试过,但这应该可以完美运行...而且速度还相当快。


3
对于strstr()函数我给出一个"+1",但是需要注意的是如果字符串中不含有"$needle",它会返回"false",因此上面提供的explode()解决方案在这种情况下更适用。 - BenMorel

3
你可以创建一个辅助函数来处理这个问题:
/**
 * Return string before needle if it exists.
 *
 * @param string $str
 * @param mixed $needle
 * @return string
 */
function str_before($str, $needle)
{
    $pos = strpos($str, $needle);

    return ($pos !== false) ? substr($str, 0, $pos) : $str;
}

Here's a use case:

$sing = 'My name is Luka. I live on the second floor.';

echo str_before($sing, '.'); // My name is Luka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接