PHP substring extraction. Get the string before the first '/' or the whole string
Asked Answered
V

14

225

I am trying to extract a substring. I need some help with doing it in PHP.

Here are some sample strings I am working with and the results I need:

home/cat1/subcat2 => home

test/cat2 => test

startpage => startpage

I want to get the string till the first /, but if no / is present, get the whole string.

I tried,

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

I think it says - get the position of / and then get the substring from position 0 to that position.

I don't know how to handle the case where there is no /, without making the statement too big.

Is there a way to handle that case also without making the PHP statement too complex?

Vetchling answered 20/12, 2009 at 14:7 Comment(1)
You might find s($str)->beforeFirst('/') helpful, as found in this standalone library.Clarisaclarise
D
305

Use explode()

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

In this case, I'm using the limit parameter to explode so that php won't scan the string any more than what's needed.

Dewaynedewberry answered 20/12, 2009 at 14:11 Comment(8)
+1 Thanks for the answer. It worked :) But one question. I am only able to do this -> $arr = explode('/',$mystring,2); echo $arr[0];. I am unable to get the first string in one statement itself - echo explode('/',$mystring,2)[0];. Since explode returns an array, I should be able to do it right? But I get an error. Any suggestions?Vetchling
Php doesn't like you indexing into return values from functions.Dewaynedewberry
oh. okay. would have been nice if it was possible.Vetchling
list($first,) = explode("/", $string, 2);Ilmenite
explode() + [0] is a long-winded way to write strtok($string, "/")Ortensia
Isn't it overkill to create a whole new array? That's what explode does.Kemppe
by the way, you can do explode("/", $string, 2)[0] in php 5.5Brooch
@Ortensia The problem with strtok() is first/second will return first but /second will return second rather than an empty string.William
F
415

The most efficient solution is the strtok function:

strtok($mystring, '/')

NOTE: In case of more than one character to split with the results may not meet your expectations e.g. strtok("somethingtosplit", "to") returns s because it is splitting by any single character from the second argument (in this case o is used).

@friek108 thanks for pointing that out in your comment.

For example:

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

and

$mystring = 'home';
$first = strtok($mystring, '/');
echo $first; // home
Ferric answered 18/6, 2014 at 8:3 Comment(6)
This is also about 40% faster than the current-explode solution. (Not that I use it so often that it matters.)Susurration
This should be the excepted answer. Definitely faster and more memory and CPU cycles efficient then any of the explode solutions given.Hackler
The problem with strtok is first/second will return first but /second will return second rather than an empty string.William
Further to my above comment: The behavior when an empty part was found changed with PHP 4.1.0. The old behavior returned an empty string, while the new, correct, behavior simply skips the part of the stringWilliam
This is not that safe in some circumstances - for example try this: echo strtok("history_table_id","_id"); . It returns simply "h". Be careful!Roseola
This however handles differently depending on if the string by which is split, is longer than 1 character.Daye
D
305

Use explode()

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

In this case, I'm using the limit parameter to explode so that php won't scan the string any more than what's needed.

Dewaynedewberry answered 20/12, 2009 at 14:11 Comment(8)
+1 Thanks for the answer. It worked :) But one question. I am only able to do this -> $arr = explode('/',$mystring,2); echo $arr[0];. I am unable to get the first string in one statement itself - echo explode('/',$mystring,2)[0];. Since explode returns an array, I should be able to do it right? But I get an error. Any suggestions?Vetchling
Php doesn't like you indexing into return values from functions.Dewaynedewberry
oh. okay. would have been nice if it was possible.Vetchling
list($first,) = explode("/", $string, 2);Ilmenite
explode() + [0] is a long-winded way to write strtok($string, "/")Ortensia
Isn't it overkill to create a whole new array? That's what explode does.Kemppe
by the way, you can do explode("/", $string, 2)[0] in php 5.5Brooch
@Ortensia The problem with strtok() is first/second will return first but /second will return second rather than an empty string.William
W
104
$first = explode("/", $string)[0];
Walleye answered 30/12, 2011 at 12:18 Comment(1)
elegant, but not very efficient in computer time. But these days folks don't care much anymore about the minute CPU cyclesCoessential
T
22

What about this :

$result = substr($mystring.'/', 0, strpos($mystring, '/'));

Simply add a '/' to the end of mystring so you can be sure there is at least one ;)

Tieshatieup answered 30/3, 2011 at 14:25 Comment(1)
You can just check if there is one slash in the string before doing this. Anyway, it's the simplest solution.Westnorthwest
H
14

Late is better than never. php has a predefined function for that. here is that good way.

strstr

if you want to get the part before match just set before_needle (3rd parameter) to 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', '/')
);
Himyarite answered 29/3, 2016 at 3:24 Comment(3)
This is not safe to use if you can't be sure that the needle exists in the string.Depreciation
@Depreciation — True, but you can always add the character to the end of the string you are checking, just to be sure.Cattier
Thanks. My tests showed that strstr is slightly faster than strtok. I will go with the former.Rakel
A
13

One-line version of the accepted answer:

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

Should work in php 5.4+

Argive answered 28/2, 2017 at 0:5 Comment(5)
Unlike the one below, the "2" limits the number of array items it creates. Good thinking.Calciferous
Is there a reason that we needed a new answer to show this condensed version of the accepted answer? Couldn't this be a comment under the accepted answer or an edit of the accepted answer?Magel
@Magel YesArgive
"Yes" to what? You agree that a comment or edit would have done the same job?Magel
@Magel NoArgive
M
9

This is probably the shortest example that came to my mind:

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

1) list() will automatically assign string until "/" if delimiter is found
2) if delimiter "/"is not found then the whole string will be assigned

...and if you get really obsessed with performance, you may add extra parameter to explode explode("/", $mystring, 2) which limits maximum of the returned elements.

Maffei answered 23/4, 2015 at 14:18 Comment(9)
I like this approach. Saves making an unnecessary array. And strtok() is unsafe.William
@rybo111: What is unsafe about strtok()?Aerial
@William I echo hakre's sentiment; what makes strtok() unsafe?Beamer
@Aerial See my replies to jmarceli's answer. It can cause unexpected behaviour depending on the PHP version.William
php 4.1.0 - rly?Aerial
@Aerial If you're > 4.1.0 (and I hope you are) then the behaviour might not be what you expect, because it'll skip empty tokens.William
A token can not be empty, and that behavior is documented. The token always starts at the first byte not a delimiter. That is, there is never an empty token. This is useful, especially for path separators when you always want the first segment or a further on segment. ///first//////second/third/Aerial
@Aerial The title of this question says "Get the string before the first '/'" - strtok will not strictly do that (as in your example), which is my point.William
The OP gives example which state that the first token has a non-zero length and strtok does exactly that for the OPs case - so if you talk about strictness, there is no unexpected behaviour of strtok here even if you skip the docs.Aerial
F
6

You can try using a regex like this:

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

sometimes, regex are slower though, so if performance is an issue, make sure to benchmark this properly and use an other alternative with substrings if it's more suitable for you.

Fitting answered 20/12, 2009 at 14:50 Comment(2)
Regex is probably overkill too, but since I say the same about explode it would be interesting to see which is faster.Kemppe
there's absolutely nothing wrong with this and I can't think of why it would deserve 2 downvotes. I personally wouldn't use regex but it's certainly not wrong.Brooch
O
5

The function strstr() in PHP 5.3 should do this job.. The third parameter however should be set to true..

But if you're not using 5.3, then the function below should work accurately:

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

I haven't tested it though, but this should work just fine.. And it's pretty fast as well

Oliveolivegreen answered 8/3, 2011 at 15:18 Comment(1)
+1 for strstr(), but be aware that it returns false if the string doesn't contain $needle, thus the explode() solutions above are a better fit in this case.Ldopa
B
4

Using current on explode would ease the process.

 $str = current(explode("/", $str, 2));
Bally answered 31/12, 2012 at 7:14 Comment(0)
A
3

You could create a helper function to take care of that:

/**
 * 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
Autoerotic answered 24/8, 2016 at 13:16 Comment(0)
V
0
$arr = explode("/", $string, 2); $first = $arr[0];

This Way is better and more accurate than strtok because if you wanna get the values before @ for example while the there's no string before @ it will give you whats after the sign . but explode doesnt

Vilmavim answered 8/2, 2023 at 16:38 Comment(0)
C
-1
$string="kalion/home/public_html";

$newstring=( stristr($string,"/")==FALSE ) ? $string : substr($string,0,stripos($string,"/"));
Causative answered 20/11, 2010 at 13:6 Comment(1)
There is absolutely zero benefit in calling a case-insensitive function when the needle is a non-letter. This code-only answer only distracts from better answers on this page, so I am voting to delete.Magel
T
-1

why not use:

function getwhatiwant($s)
{
    $delimiter='/';
    $x=strstr($s,$delimiter,true);
    return ($x?$x:$s);
}

OR:

   function getwhatiwant($s)
   {
       $delimiter='/';
       $t=explode($delimiter, $s);
       return ($t[1]?$t[0]:$s);
   }
Torque answered 19/8, 2013 at 18:44 Comment(2)
I see that there is no comment with the dv on this post, so let me explain. If the input string is 0/ then you will get an incorrect result because the ternary is just doing a falsey check. As for your your second snippet, this suffers from something that gnud's answer avoids (4 years earlier) -- the fact that you do not limit the explosions means that potentially more than 2 elements will be created, but you only need the first one. This code-only answer can safely be removed.Magel
Actually the ternary here is very nice and concise. This is a very useful method for strings that are known not to be "0$delimiter". Such as a date from which it is desired to remove sub seconds portion. The OP doesn't specify any string criteria. I found this to be very useful for what I needed. Glad it wasn't removed. I would one line it though. $substr = strstr($string, $delimiter, true) ?: $string;Bolivar

© 2022 - 2024 — McMap. All rights reserved.