Reputation: 9373
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??
Upvotes: 94
Views: 74338
Reputation: 47894
There are multiple techniques which can be used to remove a needle string from the end of another string. All snippets below will perform correctly even on multibyte strings. Some functions have nuanced behaviors which will be described.
Using preg_replace()
will seamlessly allow replacements on an array of haystack strings which may spare the need to manually implement a loop. preg_replace()
can offer more tooling around case-insensitivity, whole-word matching, and potentially cleaning up unwanted spaces or punctuation before the match (if desired). When passing a dynamic string value to a preg_
function, it is recommended to escape characters in the string with special meaning to the regex engine.
Codes: (PHPize Demo)
Use quoting markers around the needle in the pattern. This saves a preg_quote()
call, but could be broken if the needle contains \E
.
function rtrimNeedle1(string|array $haystack, string $needle): string|array {
return preg_replace("/\\Q$needle\\E$/u", '', $haystack);
}
Using preg_quote()
will be the most reliable way to escape characters in the needle string. This is probably the method that I would use professionally because it doesn't need to faff around with conditions. Because the pattern delimiter is #
, preg_quote()
doesn't need a second parameter -- this is not true if the pattern delimiters are forward slashes.
function rtrimNeedle2(string|array $haystack, string $needle): string|array {
return preg_replace('#' . preg_quote($needle) . '$#u', '', $haystack);
}
Conditionally use substr_replace()
to remove the unwanted suffix.
function rtrimNeedle3(string $haystack, string $needle): string {
return !str_ends_with($haystack, $needle)
? $haystack
: substr_replace($haystack, '', -strlen($needle));
}
Conditionally use substr()
to isolate the leading characters before the needle.
function rtrimNeedle4(string $haystack, string $needle): string {
return !str_ends_with($haystack, $needle)
? $haystack
: substr($haystack, 0, -strlen($needle));
}
Conditionally use mb_substr()
and mb_strlen()
to isolate the leading characters before the needle.
function rtrimNeedle5(string $haystack, string $needle): string {
return !str_ends_with($haystack, $needle)
? $haystack
: mb_substr($haystack, 0, -mb_strlen($needle));
}
Notice that the non-mb_
functions behave identically to the mb_
function because the offset and length parameters of substr_replace()
and substr()
both operate on bytes, not characters. Because mb_substr()
's parameters are characters, mb_strlen()
must be used in the length parameter.
Upvotes: 0
Reputation: 29679
With PHP 8, the code can be simpler.
function right_trim(string $haystack, string $needle): string {
if (str_ends_with($haystack, $needle)) {
return substr($haystack, 0, -strlen($needle));
}
return $haystack;
}
Upvotes: 0
Reputation: 1646
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;
}
Upvotes: 1
Reputation: 5552
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;
}
Upvotes: 37
Reputation: 1079
@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;
}
}
Upvotes: 0
Reputation: 1185
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 "
Upvotes: 0
Reputation: 3096
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;
}
Upvotes: 13
Reputation: 179
preg_replace and this pattern : /string\z/i
\z means end of the string
http://tr.php.net/preg_replace
Upvotes: 2
Reputation: 400972
I suppose you could use a regular expression, which would match string
and, then, end of string, coupled with the preg_replace()
function.
$str = "this is a test string";
$new_str = preg_replace('/string$/', '', $str);
string
matches... well... string
$
means end of stringFor more informations, you can read the Pattern Syntax section of the PHP manual.
Upvotes: 7
Reputation:
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);
Upvotes: 142