199

I'm just wondering how I could remove everything after a certain substring in PHP

ex:

Posted On April 6th By Some Dude

I'd like to have it so that it removes all the text including, and after, the sub string "By"

Thanks

Salman A
  • 262,204
  • 82
  • 430
  • 521
Belgin Fish
  • 19,187
  • 41
  • 102
  • 131
  • 1
    What if the sub string occurs twice (or more)? – Bart Kiers Apr 06 '10 at 22:04
  • Some relevant links demonstrating a battery of techniques with the same basic effect on different input values: [Remove everything from first occurrence of a character to the end of a string in php](https://stackoverflow.com/a/68123370/2943403) and [Remove optional time component from datetime stamp string](https://stackoverflow.com/a/68870005/2943403), [Remove all characters after a specific character](https://stackoverflow.com/q/9315856) – mickmackusa Nov 04 '21 at 23:41

15 Answers15

378
$variable = substr($variable, 0, strpos($variable, "By"));

In plain english: Give me the part of the string starting at the beginning and ending at the position where you first encounter the deliminator.

Austin Fitzpatrick
  • 7,243
  • 3
  • 25
  • 22
  • 17
    What about "only do this if "by" exists? – Alisso Apr 14 '13 at 05:00
  • 4
    You're right. strpos will return FALSE if "By" is not found. substr will return an empty string if the length given is false. In practice it would probably be useful to check whether "By" exists and then only doing this if it does (otherwise just leaving the string alone). – Austin Fitzpatrick Apr 15 '13 at 20:42
  • I put an answer which I think addresses everything below and also explains ways to deal with all kinds of things like case insensitive, multiple occurrences, and regular expressions. If anyone wants to do anything more flexible or doesn't have control over the input coming in it's probably worth checking out. – azoundria Aug 22 '17 at 23:28
  • What to do if the string after what I want to remove everything is "\n". I tried: $skill_current = substr($skill_current, 0, strpos($skill_current, "\n")); and I tried $skill_current = substr($skill_current, 0, strpos($skill_current, "\\n")); - didn't work – Kaspar L. Palgi Sep 06 '18 at 15:43
  • `\public static function removeContentAfter(string $string, string $after): string { return false !== ($pos = strpos($string, $after)) ? substr($string, 0, $pos) : $string; }` returns original if the "By" is not found – E Ciotti Jun 18 '19 at 11:41
  • Generally, use rather `mb_substr` and `mb_strpos` to be safe for most of languages – jave.web Dec 04 '20 at 12:23
  • Replace "By" with 'By' to be faster – Michal - wereda-net Jun 02 '22 at 16:58
  • I don't know why this is so highly-rated. If the strpos returns false then the substr will return empty. – SteveExdia Apr 25 '23 at 17:58
128

If you're using PHP 5.3+ take a look at the $before_needle flag of strstr()

$s = 'Posted On April 6th By Some Dude';
echo strstr($s, 'By', true);
VolkerK
  • 95,432
  • 20
  • 163
  • 226
  • 80
    Note that it will return `FALSE` if portion of string is not found. So the solution could be: `echo strstr($s, 'By', true) ?: $s;` – kenorb Feb 22 '15 at 01:07
  • 1
    kenorb's commented solution, is not bulletproof. It will fail when the returned substring is _falsey_. Proof: https://3v4l.org/4kYeU – mickmackusa Nov 04 '21 at 22:24
  • @mickmackusa Good point. What would you suggest to resolve this - a multi-line check or is there a better single line alternative to `echo strstr($s, 'By', true) === false ? $s : strstr($s, 'By', true)`? – Steve Chambers Oct 14 '22 at 20:41
  • 1
    @Steve the PHP manual contains an explicit Note that `strstr()` should not be used to check the existence of a string in another string -- it recommends using `strpos()` for performance reasons. That said, I would seek a single function call. Choosing the right technique depends on the desired output when the needle is not found in the haystack. I have posted some links under the question. – mickmackusa Oct 14 '22 at 23:21
  • 1
    Good point about `strstr` @mickmackusa. Although there a lot of answers here I wasn't 100% satisfied with any of them so have added my own from the above advice: https://stackoverflow.com/questions/2588666#answer-74077611 (please feel free to review). – Steve Chambers Oct 15 '22 at 07:44
52

How about using explode:

$input = 'Posted On April 6th By Some Dude';
$result = explode(' By',$input);
return $result[0];

Advantages:

squarecandy
  • 4,894
  • 3
  • 34
  • 45
  • @bkac - What's wrong with old fashioned as long as it works and is not depreciated? – squarecandy Oct 05 '16 at 20:34
  • 6
    This eliminates the extra check for the existence of the delimiter string required by the accepted answer. –  Oct 18 '16 at 19:56
  • It is unnecessary to explode on _all_ `By` substrings in the string, so the `explode()` call should include a limit parameter of `2`. Disadvantage of using `explode()` is that you need to generate a temporary array on your way to isolating the desired string. – mickmackusa Nov 04 '21 at 22:26
  • That's a good point about adding the limit parameter. I think it doesn't matter so much if you're dealing with a fairly predictable data set - like in the example if it's always "Post On {date} By {name}". But, yeah, adding a limit of two is a good sanity check. It would also make the author name still usable in $result[1] if the name was "Byron Byronson" or whatever. In term of generating an unnecessary array - I think the speed and code readability vs. using a regex based function is worth it. – squarecandy Nov 05 '21 at 13:50
27

You could do:

$posted = preg_replace('/ By.*/', '', $posted);
echo $posted;

This is a regular expression replacer function that finds the literal string ' By' and any number of characters after it (.*) and replaces them with an empty string (''), storing the result in the same variable ($posted) that was searched.

If [space]By is not found in the input string, the string remains unchanged.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
JYelton
  • 35,664
  • 27
  • 132
  • 191
16

One method would be:

$str = 'Posted On April 6th By Some Dude';
echo strtok($str, 'By'); // Posted On April 6th
samlev
  • 5,852
  • 1
  • 26
  • 38
HADI
  • 2,829
  • 1
  • 26
  • 26
  • This is the best answer it works even if By is not in the string, substr answer is wrong because is by doest'nt exist it fails. – neoteknic Nov 30 '17 at 12:31
  • 1
    This is incorrect: the function won't split by `By`, but by any char in the 2nd parameter. Meaning, it will split by either `B` or `y`. Technically, it's not getting everything before a `By`. – msb Feb 06 '19 at 02:33
  • 1
    Be careful: strtok will return the portion of the string *after* the character if it is the first character in the string, e.g., `strtok('a:b', ':')` will return `a` but `strtok(':b', ':')` will return `b`, not an empty string as you'd expect. – Quinn Comendant May 25 '19 at 03:01
12

Try this.

function strip_after_string($str,$char)
    {
        $pos=strpos($str,$char);    
        if ($pos!==false) 
        {
            //$char was found, so return everything up to it.
            return substr($str,0,$pos);
        } 
        else 
        {
            //this will return the original string if $char is not found.  if you wish to return a blank string when not found, just change $str to ''
            return $str; 
        }
    }

Usage:

<?php
    //returns Apples
    $clean_string= strip_after_string ("Apples, Oranges, Banannas",",");
?>
always-a-learner
  • 3,671
  • 10
  • 41
  • 81
Tim Yobson
  • 121
  • 1
  • 2
6

Austin's answer works for your example case.

More generally, you would do well to look into the regular expression functions when the substring you're splitting on may differ between strings:

$variable = preg_replace('/By.*/', '', $variable);
jemfinch
  • 2,851
  • 19
  • 24
4

preg_replace offers one way:

$newText = preg_replace('/\bBy\b.*$/', '', $text);

The '\b' matches on a word boundary (it's zero-width and matches between word and non-word characters), ensuring it will only match a complete word. While the target word doesn't occur as part of any other words in the example, in general the target might appear as part of another word (e.g. "by" in "'Babylon Revisited', by F. Scott Fitzgerald" or "'Bloom County Babylon' by Berkely Breathed").

The '.*$' matches all text up to the end. '$' matches the end of the string and, while not strictly necessary for correctness, documents the intent of the regex (which are well known for becoming hard to read).

Regular expression matching starts at the start of the string, so this will replace starting at the first match. For how to instead match starting at the last, see "How to replace only the last match of a string with preg_replace?"

outis
  • 75,655
  • 22
  • 151
  • 221
  • Some explanation of what the pattern does and why it is a good idea would make this answer more helpful to researchers. Perhaps explain why this answer is superior to other techniques posted on this page. – mickmackusa Nov 04 '21 at 23:07
4
$var = "Posted On April 6th By Some Dude";
$new_var = substr($var, 0, strpos($var, " By"));
Protomen
  • 9,471
  • 9
  • 57
  • 124
  • This unexplained answer suffers the same vulnerability as the accepted answer because there is no explicit `=== false` check. When the needle is not found, the entire string is truncated. I would expect to see the whole input string, but I get a zero-length string. https://3v4l.org/f7ue2 – mickmackusa Nov 04 '21 at 23:11
4

You can use list and explode functions:

list($result) = explode("By", "Posted On April 6th By Some Dude", 2);
// $result is "Posted On April 6th "
Salman A
  • 262,204
  • 82
  • 430
  • 521
2

By using regular expression: $string = preg_replace('/\s+By.*$/', '', $string)

Ming-Tang
  • 17,410
  • 8
  • 38
  • 76
2

Below is the most efficient method (by run-time) to cut off everything after the first By in a string. If By does not exist, the full string is returned. The result is in $sResult.

$sInputString = "Posted On April 6th By Some Dude";
$sControl = "By";

//Get Position Of 'By'
$iPosition = strpos($sInputString, " ".$sControl);
if ($iPosition !== false)
  //Cut Off If String Exists
  $sResult = substr($sInputString, 0, $iPosition);
else
  //Deal With String Not Found
  $sResult = $sInputString;

//$sResult = "Posted On April 6th"

If you don't want to be case sensitive, use stripos instead of strpos. If you think By might exist more than once and want to cut everything after the last occurrence, use strrpos.

Below is a less efficient method but it takes up less code space. This method is also more flexible and allows you to do any regular expression.

$sInputString = "Posted On April 6th By Some Dude";
$pControl = "By";

$sResult = preg_replace("' ".$pControl.".*'s", '', $sInputString);

//$sResult = "Posted On April 6th"

For example, if you wanted to remove everything after the day:

$sInputString = "Posted On April 6th By Some Dude";
$pControl = "[0-9]{1,2}[a-z]{2}"; //1 or 2 numbers followed by 2 lowercase letters.

$sResult = preg_replace("' ".$pControl.".*'s", '', $sInputString);

//$sResult = "Posted On April"

For case insensitive, add the i modifier like this:

$sResult = preg_replace("' ".$pControl.".*'si", '', $sInputString);

To get everything past the last By if you think there might be more than one, add an extra .* at the beginning like this:

$sResult = preg_replace("'.* ".$pControl.".*'si", '', $sInputString);

But here is also a really powerful way you can use preg_match to do what you may be trying to do:

$sInputString = "Posted On April 6th By Some Dude";

$pPattern = "'Posted On (.*?) By (.*?)'s";
if (preg_match($pPattern, $sInputString, $aMatch)) {
  //Deal With Match
  //$aMatch[1] = "April 6th"
  //$aMatch[2] = "Some Dude"
} else {
  //No Match Found
}

Regular expressions might seem confusing at first but they can be really powerful and your best friend once you master them! Good luck!

azoundria
  • 940
  • 1
  • 8
  • 24
1

Use the strstr function.

<?php
$myString = "Posted On April 6th By Some Dude";
$result = strstr($myString, 'By', true);

echo $result ;

The third parameter true tells the function to return everything before first occurrence of the second parameter.

Faisal
  • 4,591
  • 3
  • 40
  • 49
1

Why...

This is likely overkill for most people's needs, but, it addresses a number of things that each individual answer above does not. Of the items it addresses, three of them were needed for my needs. With tight bracketing and dropping the comments, this could still remain readable at only 13 lines of code.

This addresses the following:

  • Performance impact of using REGEX vs strrpos/strstr/strripos/stristr.
  • Using strripos/strrpos when character/string not found in string.
  • Removing from left or right side of string (first or last occurrence) .
  • CaSe Sensitivity.
  • Wanting the ability to return back the original string unaltered if search char/string not found.

Usage:

Send original string, search char/string, "R"/"L" for start on right or left side, true/false for case sensitivity. For example, search for "here" case insensitive, in string, start right side.

echo TruncStringAfterString("Now Here Are Some Words Here Now","here","R",false);

Output would be "Now Here Are Some Words ". Changing the "R" to an "L" would output: "Now ".

Here's the function:

function TruncStringAfterString($origString,$truncChar,$startSide,$caseSensitive)
{
    if ($caseSensitive==true && strstr($origString,$truncChar)!==false)
    {
        // IF START RIGHT SIDE:
        if (strtoupper($startSide)=="R" || $startSide==false)
        {   // Found, strip off all chars from truncChar to end
            return substr($origString,0,strrpos($origString,$truncChar));
        }

        // IF START LEFT SIDE: 
        elseif (strtoupper($startSide)=="L" || $startSide="" || $startSide==true)
        {   // Found, strip off all chars from truncChar to end
            return strstr($origString,$truncChar,true);
        }           
    }
    elseif ($caseSensitive==false && stristr($origString,$truncChar)!==false)
    {           
        // IF START RIGHT SIDE: 
        if (strtoupper($startSide)=="R" || $startSide==false)
        {   // Found, strip off all chars from truncChar to end
            return substr($origString,0,strripos($origString,$truncChar));
        }

        // IF START LEFT SIDE: 
        elseif (strtoupper($startSide)=="L" || $startSide="" || $startSide==true)
        {   // Found, strip off all chars from truncChar to end
            return stristr($origString,$truncChar,true);
        }
    }       
    else
    {   // NOT found - return origString untouched
        return $origString;     // Nothing to do here
    }           

}
Robert Mauro
  • 566
  • 8
  • 17
  • If you downvote my working answer, it would be appreciated it you stated why. – Robert Mauro Aug 22 '19 at 20:25
  • There is a specific note in the php manual on the `strstr()` page that states: "_If you only want to determine if a particular needle occurs within haystack, use the faster and less memory intensive function strpos() instead._" https://www.php.net/manual/en/function.strstr (I did not dv this answer, but I see a couple of assignment declaration where I think you intend to check if `$startSide` loosely equals a zero-length string.) – mickmackusa Nov 04 '21 at 23:31
  • @mickmackusa thanks. I used strstr() to avoid the extra handling necessary to handle varying type return strings (booleans and ints, depending) as well as to make sure neither 0 was handled as first, nor true as second character. I'll give it a look again this coming week and see what changes I can make. Much thanks for the input and holding off on the DV!!! – Robert Mauro Nov 05 '21 at 12:47
-3
$variable = substr($initial, 0, strpos($initial, "By"));

if (!empty($variable)) { echo $variable; } else { echo $initial; }
MatejMecka
  • 1,448
  • 2
  • 24
  • 37
  • This unexplained answer makes the same mistake that the accepted answer makes in that it does not explicitly check if `strpos()` returns `false` (versus `0`). Worse, this answer again makes a falsey check on the string returned from `substr()` which may also lead to incorrect results. There isn't much worth keeping about this answer. – mickmackusa Nov 04 '21 at 23:35