89

I need to remove a substring of a string, but only when it is at the END of the string.

for example, removing 'string' at the end of the following strings :

"this is a test string" ->  "this is a test "
"this string is a test string" - > "this string is a test "
"this string is a test" -> "this string is a test"

Any idea's ? Probably some kind of preg_replace, but how??

Dylan
  • 9,129
  • 20
  • 96
  • 153
  • You might find [`s($str)->replaceSuffix('string')`](https://github.com/delight-im/PHP-Str/blob/ea3e40132e9d4ce27da337dae6286f2478b15f56/src/Str.php#L442) helpful, as found in [this standalone library](https://github.com/delight-im/PHP-Str). – caw Jul 28 '16 at 04:10

8 Answers8

136

You'll note the use of the $ character, which denotes the end of a string:

$new_str = preg_replace('/string$/', '', $str);

If the string is a user supplied variable, it is a good idea to run it through preg_quote first:

$remove = $_GET['remove']; // or whatever the case may be
$new_str = preg_replace('/'. preg_quote($remove, '/') . '$/', '', $str);
  • will preg_quote/preg_replace work with non ASCII (say UTF-8) strings as well ? i.e. to say are `preg_*` function families aware of encoding ? What about `[^[:alnum:]]` character class ? – wadkar Nov 14 '11 at 16:40
  • 1
    This doesn't remove the space before "string" if it were to exist. You could also just use substring on the last 6 characters, compare them to "string", and if it's a match, substring them out. It'd be much faster than Regex. – Cole Tobin Aug 17 '13 at 07:30
  • 2
    This should not be the accepted answer. Using preg_replace for this task is ugly as hell, wrong in logic, and a total waste of server energy/time/cycles (yes, it matters, you pay your hosting more because 10000000 of other users' web pages use preg_replace instead of substr) – FrancescoMM Sep 16 '16 at 09:48
35

Using regexp may fails if the substring has special characters.

The following will work with any strings and follows conventions used by built-in string functions:

function right_trim(string $haystack, string $needle): string {
    $needle_length = strlen($needle);
    if (substr($haystack, -$needle_length) === $needle) {
        return substr($haystack, 0, -$needle_length);
    }
    return $haystack;
}
Igor Klimer
  • 15,321
  • 3
  • 47
  • 57
Skrol29
  • 5,402
  • 1
  • 20
  • 25
  • 14
    the last bit can be simply `$str = substr($str, 0, -strlen($substring));` upvoted as good alternative for regex. I came up with same answer for my problem. I would use pure string functions over `preg_*` families anytime if it serves my purpose – wadkar Nov 14 '11 at 16:37
  • 2
    a simple and smart solution for a supposedly simple problem without using regular expressions. thanks – alds Dec 17 '15 at 08:30
  • 1
    As some say "if your solution requires regex, now you have two problems". So for the fun of it I wanted to solve this problem for non-regex and I had come with exactly this and @Sudhi's comment before seeing your answer. The little piece I wasn't aware of was that you can place "-" to negate rather than multiplying by -1. So thanks. – ChronoFish Mar 29 '18 at 15:00
  • 1
    Just a note: should use mb_* functions to be safe for special char (eg: áéã, etc) – MJC Mar 04 '19 at 14:22
  • @Sudhi, thanks for the tip! I've edited the question to use it. I've also reformatted the code so that it's a function and it follows conventions used by built-in string functions. Hope this helps! – Igor Klimer Jul 11 '22 at 16:38
12

I wrote these two function for left and right trim of a string:

/**
 * @param string    $str           Original string
 * @param string    $needle        String to trim from the end of $str
 * @param bool|true $caseSensitive Perform case sensitive matching, defaults to true
 * @return string Trimmed string
 */
function rightTrim($str, $needle, $caseSensitive = true)
{
    $strPosFunction = $caseSensitive ? "strpos" : "stripos";
    if ($strPosFunction($str, $needle, strlen($str) - strlen($needle)) !== false) {
        $str = substr($str, 0, -strlen($needle));
    }
    return $str;
}

/**
 * @param string    $str           Original string
 * @param string    $needle        String to trim from the beginning of $str
 * @param bool|true $caseSensitive Perform case sensitive matching, defaults to true
 * @return string Trimmed string
 */
function leftTrim($str, $needle, $caseSensitive = true)
{
    $strPosFunction = $caseSensitive ? "strpos" : "stripos";
    if ($strPosFunction($str, $needle) === 0) {
        $str = substr($str, strlen($needle));
    }
    return $str;
}
Bas
  • 3,016
  • 3
  • 22
  • 18
6

I suppose you could use a regular expression, which would match string and, then, end of string, coupled with the preg_replace() function.


Something like this should work just fine :

$str = "this is a test string";
$new_str = preg_replace('/string$/', '', $str);


Notes :

  • string matches... well... string
  • and $ means end of string

For more informations, you can read the Pattern Syntax section of the PHP manual.

Pascal MARTIN
  • 395,085
  • 80
  • 655
  • 663
2

preg_replace and this pattern : /string\z/i

\z means end of the string

http://tr.php.net/preg_replace

Errico Malatesta
  • 179
  • 1
  • 13
0

IF you don't mind about performance AND the part of the string could be placed only at the end of string, THEN you can do this:

$string = "this is a test string";
$part = "string";
$string = implode( $part, array_slice( explode( $part, $string ), 0, -1 ) );
echo $string;
// OUTPUT: "this is a test "
Marco Panichi
  • 1,068
  • 1
  • 18
  • 31
0

@Skrol29's answer is the best, but here it is in function form and using the ternary operator:

if (!function_exists('str_ends_with')) {
    function str_ends_with($haystack, $suffix) {
        $length = strlen( $suffix );
        if( !$length ) {
            return true;
        }
        return substr( $haystack, -$length ) === $suffix;
    }
}

if (!function_exists('remove_suffix')) {
    function remove_suffix ($string, $suffix) {
        return str_ends_with($string, $suffix) ? substr($string, 0, strlen($string) - strlen($suffix)) : $string;
    }
}
kloddant
  • 1,026
  • 12
  • 19
0

PHP 8 version

function removePostfix(string $haystack, string $needle): string
{
    if (str_ends_with($haystack, $needle)) {
        return substr($haystack, 0, strlen($haystack) - strlen($needle));
    }


    return $haystack;
}
Artem
  • 1,426
  • 12
  • 17