如何从字符串的末尾删除子字符串(删除字符串的后缀)?

562

7
__strip__会将给定的字符从字符串两端去除,对于你的情况,它会去除"."、"c"、"o"和"m"。 - mthurlin
7
它还会从字符串前面删除那些字符。如果你只希望从结尾处删除,请使用 rstrip()。 - Andre Miller
61
是的,str.strip并不是你想象中的那样。str.strip会从字符串的开头和结尾删除指定的任何字符。因此,"acbacda".strip("ad")将给出'cbac';开头的a和结尾的da被删除了。谢谢。 - scvalex
6
另外,这样可以以 任何顺序 删除字符:"site.ocm" > "site"。 - Eric O. Lebigot
8
@scvalex,哇哦,刚刚意识到在使用这种方法很久后它是很危险的,因为代码通常仍能正常工作。 - Flash
显示剩余4条评论
25个回答

6

对于URL(由于给定的示例似乎是该主题的一部分),可以这样做:

import os
url = 'http://www.stackoverflow.com'
name,ext = os.path.splitext(url)
print (name, ext)

#Or:
ext = '.'+url.split('.')[-1]
name = url[:-len(ext)]
print (name, ext)

两者的输出结果都为:('http://www.stackoverflow', '.com')

如果你只想要分割".com"或其他特定字符串,也可以与str.endswith(suffix)结合使用。


5

假设您想删除域名,无论是什么 (.com, .net, 等等)。我建议找到 . 并删除从该点开始的所有内容。

url = 'abcdc.com'
dot_index = url.rfind('.')
url = url[:dot_index]

在这里,我使用rfind来解决像abcdc.com.net这样的URL问题,该问题应缩短为名称abcdc.com

如果您也关注www.,则应明确检查它们:

if url.startswith("www."):
   url = url.replace("www.","", 1)

replace函数中的1是用于处理奇怪的边界情况,比如www.net.www.com

如果你的url更加复杂,请查看其他人提供的正则表达式答案。


4

如果你只是想剥离文件扩展名:

'.'.join('abcdc.com'.split('.')[:-1])
# 'abcdc'

它适用于任何扩展名,文件名中可能还存在其他点。它仅在点上将字符串拆分为列表,并在最后一个元素之前连接。

3

因为这是一个非常流行的问题,我添加了另一个现在可用的解决方案。使用Python 3.9 (https://docs.python.org/3.9/whatsnew/3.9.html),将添加函数removesuffix()(和removeprefix()),这个函数正是在这里所询问的。

url = 'abcdc.com'
print(url.removesuffix('.com'))

输出:

'abcdc'

PEP 616 (https://www.python.org/dev/peps/pep-0616/) 显示了它的行为方式(这不是真正的实现):

def removeprefix(self: str, prefix: str, /) -> str:
    if self.startswith(prefix):
        return self[len(prefix):]
    else:
        return self[:]

并且它相对于自行实现的解决方案具有以下好处

  1. 更加稳定: 代码不会依赖于用户计算文字长度。

  2. 更高效: 代码无需调用Python内置的len函数或更昂贵的str.replace()方法。

  3. 更具描述性: 这些方法提供了更高级别的API,有助于提高代码可读性,而不是传统的字符串切片方法。


1
有人在你之前8个月就已经发布了关于这个问题的帖子 https://dev59.com/lXNA5IYBdhLWcg3wPbSe#61432508 - user3064538

3
如果需要去掉字符串的末尾(如果存在)否则什么都不做。 我的最佳解决方案。 你可能想使用前两种实现中的其中一种,但我为了完整性而包含了第三种。
对于一个固定的后缀:
def remove_suffix(v, s):
    return v[:-len(s)] if v.endswith(s) else v
remove_suffix("abc.com", ".com") == 'abc'
remove_suffix("abc", ".com") == 'abc'

对于一个正则表达式:

def remove_suffix_compile(suffix_pattern):
    r = re.compile(f"(.*?)({suffix_pattern})?$")
    return lambda v: r.match(v)[1]
remove_domain = remove_suffix_compile(r"\.[a-zA-Z0-9]{3,}")
remove_domain("abc.com") == "abc"
remove_domain("sub.abc.net") == "sub.abc"
remove_domain("abc.") == "abc."
remove_domain("abc") == "abc"

对于一组常量后缀,大量调用的渐近最快方法:

def remove_suffix_preprocess(*suffixes):
    suffixes = set(suffixes)
    try:
        suffixes.remove('')
    except KeyError:
        pass

    def helper(suffixes, pos):
        if len(suffixes) == 1:
            suf = suffixes[0]
            l = -len(suf)
            ls = slice(0, l)
            return lambda v: v[ls] if v.endswith(suf) else v
        si = iter(suffixes)
        ml = len(next(si))
        exact = False
        for suf in si:
            l = len(suf)
            if -l == pos:
                exact = True
            else:
                ml = min(len(suf), ml)
        ml = -ml
        suffix_dict = {}
        for suf in suffixes:
            sub = suf[ml:pos]
            if sub in suffix_dict:
                suffix_dict[sub].append(suf)
            else:
                suffix_dict[sub] = [suf]
        if exact:
            del suffix_dict['']
            for key in suffix_dict:
                suffix_dict[key] = helper([s[:pos] for s in suffix_dict[key]], None)
            return lambda v: suffix_dict.get(v[ml:pos], lambda v: v)(v[:pos])
        else:
            for key in suffix_dict:
                suffix_dict[key] = helper(suffix_dict[key], ml)
            return lambda v: suffix_dict.get(v[ml:pos], lambda v: v)(v)
    return helper(tuple(suffixes), None)
domain_remove = remove_suffix_preprocess(".com", ".net", ".edu", ".uk", '.tv', '.co.uk', '.org.uk')

最终,在Pypy中,这个版本可能比CPython快得多。对于几乎所有不涉及大量可能无法轻松表示为正则表达式的后缀字典的情况,该正则表达式变体可能比此版本更快,至少在CPython中如此。
在Pypy中,即使re模块使用DFA编译正则表达式引擎,基本上所有lambda的开销都会被JIT优化掉,因此对于大量调用或长字符串,正则表达式变体几乎肯定会变慢。
但是在CPython中,事实上,运行正则表达式比较的C代码几乎肯定会超过后缀集合版本的算法优势,几乎在所有情况下都是如此。
编辑:https://m.xkcd.com/859/

2
import re

def rm_suffix(url = 'abcdc.com', suffix='\.com'):
    return(re.sub(suffix+'$', '', url))

我希望以最能表达的方式重申这个答案。当然,以下方法会占用更少的CPU时间:

def rm_dotcom(url = 'abcdc.com'):
    return(url[:-4] if url.endswith('.com') else url)

然而,如果CPU是瓶颈,为什么要用Python编写代码呢?

那么什么情况下CPU会成为瓶颈呢?也许在驱动程序中。

使用正则表达式的优点是代码可重用性。如果您想要删除仅有三个字符的“.me”呢?同样的代码就可以解决问题:

代码如下:

>>> rm_sub('abcdc.me','.me')
'abcdc'

1
在我的情况下,我需要引发一个异常,因此我这样做:
class UnableToStripEnd(Exception):
    """A Exception type to indicate that the suffix cannot be removed from the text."""

    @staticmethod
    def get_exception(text, suffix):
        return UnableToStripEnd("Could not find suffix ({0}) on text: {1}."
                                .format(suffix, text))


def strip_end(text, suffix):
    """Removes the end of a string. Otherwise fails."""
    if not text.endswith(suffix):
        raise UnableToStripEnd.get_exception(text, suffix)
    return text[:len(text)-len(suffix)]

1
你可以使用 `split`:
'abccomputer.com'.split('.com',1)[0]
# 'abccomputer'

9
a = 'www.computerbugs.com' 时,结果为 'www' - yairchu
我猜可以从反向来做?不确定是否有更易读的写法:'www.computerbugs.com'[::-1].split('.com'[::-1], 1)[-1][::-1] - Ben Farmer
Ah rsplit就是方法:'www.computerbugs.com'.rsplit('.com', 1)[0] - Ben Farmer

1

更广泛的解决方案,增加了“替换后缀”(可以通过替换为空字符串来移除)和“设置最大替换次数”的可能性:

def replacesuffix(s,old,new='',limit=1):
    """
    String suffix replace; if the string ends with the suffix given by parameter `old`, such suffix is replaced with the string given by parameter `new`. The number of replacements is limited by parameter `limit`, unless `limit` is negative (meaning no limit).

    :param s: the input string
    :param old: the suffix to be replaced
    :param new: the replacement string. Default value the empty string (suffix is removed without replacement).
    :param limit: the maximum number of replacements allowed. Default value 1.
    :returns: the input string with a certain number (depending on parameter `limit`) of the rightmost occurrences of string given by parameter `old` replaced by string given by parameter `new`
    """
    if s[len(s)-len(old):] == old and limit != 0:
        return replacesuffix(s[:len(s)-len(old)],old,new,limit-1) + new
    else:
        return s

在您的情况下,考虑到默认参数,可以通过以下方式获得所需结果:
replacesuffix('abcdc.com','.com')
>>> 'abcdc'

一些更一般的例子:
replacesuffix('whatever-qweqweqwe','qwe','N',2)
>>> 'whatever-qweNN'

replacesuffix('whatever-qweqweqwe','qwe','N',-1)
>>> 'whatever-NNN'

replacesuffix('12.53000','0',' ',-1)
>>> '12.53   '

1

在Python 3.8中移除后缀的函数:

def removesuffix(text, suffix):
if text.endswith(suffix):
    return text[:-len(suffix)]
else:
    return text

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