从字符串中删除一个部分,但仅当它在字符串的末尾时。

92

我需要删除一个字符串的子串,但只有在该子串位于该字符串结尾时才进行删除。

例如,在以下字符串的结尾处删除“string”:

"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"

有什么想法吗?可能需要使用 preg_replace,但是怎么做呢?


你可能会发现s($str)->replaceSuffix('string')很有帮助,可以在这个独立库中找到。 - caw
8个回答

137

请注意使用了 $ 字符,它表示字符串的结尾:

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

如果字符串是由用户提供的变量,最好先通过preg_quote进行处理:

$remove = $_GET['remove']; // or whatever the case may be
$new_str = preg_replace('/'. preg_quote($remove, '/') . '$/', '', $str);

preg_quote/preg_replace可以处理非ASCII(比如UTF-8)字符串吗?也就是说,preg_*函数族是否意识到编码?那么[^[:alnum:]]字符类呢? - Sudhi
1
如果存在,则此操作不会删除“string”之前的空格。您也可以只在最后6个字符上使用substring,将它们与“ string”进行比较,如果匹配,则将它们substring出来。这比正则表达式快得多。 - Cole Tobin
2
这不应该是被接受的答案。使用 preg_replace 来完成这个任务非常丑陋,逻辑上是错误的,而且浪费服务器的能源/时间/周期(是的,这很重要,因为其他用户的网页中有 10000000 个使用 preg_replace 而不是 substr)。 - FrancescoMM

36

如果子字符串包含特殊字符,使用正则表达式可能会失败。

下面的方法适用于任何字符串,并遵循内置字符串函数所使用的约定:

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;
}

14
最后一部分可以简单地使用 $str = substr($str, 0, -strlen($substring)); 作为正则表达式的良好替代品。我对我的问题得出了同样的答案。如果它能够满足我的目的,我会随时使用纯字符串函数而不是 preg_* 函数族。 - Sudhi
2
一个看似简单的问题,却不使用正则表达式的简单而聪明的解决方案。谢谢。 - alds
1
正如有些人所说的“如果你的解决方案需要正则表达式,那么你现在有两个问题了”。所以为了好玩,我想用非正则表达式来解决这个问题,在看到你的答案之前,我已经想出了这个和@Sudhi的评论。我不知道的小细节是,你可以使用“-”来否定,而不是乘以-1。所以谢谢。 - ChronoFish
1
请注意:应使用mb_*函数以确保对特殊字符(例如:áéã等)的安全处理。 - MJC
@Sudhi,感谢你的提示!我已经编辑了问题并使用了它。我还重新格式化了代码,使其成为一个函数,并遵循内置字符串函数使用的约定。希望这有所帮助! - Igor Klimer

13

我写了以下两个函数用于去除字符串的左侧或右侧空格:

/**
 * @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;
}

7

我想你可以使用正则表达式,它可以匹配字符串,然后再匹配字符串结尾,再结合preg_replace()函数。


像这样的东西应该可以很好地工作:

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


注意:

  • string 匹配…嗯… string
  • 而且 $ 表示字符串的结尾

如需了解更多信息,您可以阅读 PHP 手册的 Pattern Syntax 部分。


2

0

如果您不关心性能,且字符串的部分仅可放置在字符串末尾,则可以这样做:

$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 "

0
@Skrol29的答案是最好的,但是这里是以函数形式并使用三元运算符的方式呈现:
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;
    }
}

0

PHP 8版本

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


    return $haystack;
}

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