如何从字符串末尾删除子字符串?
Posted
技术标签:
【中文标题】如何从字符串末尾删除子字符串?【英文标题】:How do I remove a substring from the end of a string? 【发布时间】:2010-11-05 13:06:50 【问题描述】:我有以下代码:
url = 'abcdc.com'
print(url.strip('.com'))
我期待:abcdc
我得到了:abcd
现在可以了
url.rsplit('.com', 1)
有没有更好的办法?
【问题讨论】:
strip 去掉字符串两端给出的字符,在你的情况下,它去掉“.”、“c”、“o”和“m”。跨度> 它还会从字符串的前面删除这些字符。如果您只想将其从末尾删除,请使用 rstrip() 是的。 str.strip 不会做你认为它做的事情。 str.strip 删除从字符串的开头和结尾指定的任何字符。所以, "acbacda".strip("ad") 给出 'cbac';开头的 a 和结尾的 da 被剥离。干杯。 另外,这会删除任意顺序中的字符:“site.ocm”>“site”。 @scvalex,哇,这才意识到这已经使用了很长时间了——这很危险,因为代码经常碰巧正常工作 【参考方案1】:strip
并不意味着“删除此子字符串”。 x.strip(y)
将y
视为一组字符,并从x
的两端删除该组中的所有字符。
在 Python 3.9 和更新版本上,您可以使用 removeprefix
和 removesuffix
方法从字符串的任一侧删除整个子字符串:
url = 'abcdc.com'
url.removesuffix('.com') # Returns 'abcdc'
url.removeprefix('abcdc.') # Returns 'com'
相关的 Python 增强提案是PEP-616。
在 Python 3.8 及更早版本上,您可以使用 endswith
和切片:
url = 'abcdc.com'
if url.endswith('.com'):
url = url[:-4]
或regular expression:
import re
url = 'abcdc.com'
url = re.sub('\.com$', '', url)
【讨论】:
是的,我自己认为第一个例子,带有endswith() 测试,会更好;正则表达式会涉及一些性能损失(解析正则表达式等)。我不会选择 rsplit() ,但那是因为我不知道你到底想要达到什么目的。我认为当且仅当它出现在 url 的末尾时,它才会删除 .com?如果您将 rsplit 解决方案用于“www.commercialthingie.co.uk”等域名,则会给您带来麻烦url = url[:-4] if any(url.endswith(x) for x in ('.com','.net')) else url
如果我写EXAMLPLE.COM
域名不区分大小写怎么办。 (这是对正则表达式解决方案的投票)
这不是重写,rsplit()
解决方案与endswith()
的行为不同,当原始字符串末尾没有子字符串,但在中间某处时.例如:"www.comeandsee.com".rsplit(".com",1)[0] == "www.comeandsee"
但"www.comeandsee.net".rsplit(".com",1)[0] == "www"
语法s[:-n]
有一个警告:对于n = 0
,这不会返回截断最后一个零字符的字符串,而是返回空字符串。【参考方案2】:
如果您确定字符串只出现在末尾,那么最简单的方法是使用“替换”:
url = 'abcdc.com'
print(url.replace('.com',''))
【讨论】:
这也将替换像www.computerhope.com
这样的url。检查endswith()
应该没问题。
"www.computerhope.com".endswith(".com")
是真的,它仍然会崩溃!
“如果你确定字符串只出现在末尾”是指“如果你确定子字符串只出现一次”吗?当子字符串位于中间时,替换似乎也有效,但正如其他评论所暗示的那样,它将替换子字符串的任何出现,为什么它应该在最后我不明白【参考方案3】:
def strip_end(text, suffix):
if suffix and text.endswith(suffix):
return text[:-len(suffix)]
return text
【讨论】:
@Boris 之前喜欢过,不用额外检查后缀是否为空 @yarichu 我从PEP 616 复制了代码,该代码将这个确切的函数引入了stdlib。我也认为这种方式更好的原因是你必须做len(text)-len(suffix)
的原因是不清楚什么时候你可以在 Python 中使用负索引(事实上,你在编辑中修复了那个错误并且曾经有一个评论在这里错误地告诉您不需要len(text)
,因此这似乎容易出错),而if suffix
则清楚地说明了您实际上检查的内容以及原因。【参考方案4】:
因为似乎还没有人指出这一点:
url = "www.example.com"
new_url = url[:url.rfind(".")]
这应该比使用split()
的方法更有效,因为没有创建新的列表对象,并且此解决方案适用于具有多个点的字符串。
【讨论】:
哇,这是一个不错的技巧。我不能让它失败,但我也很难想出可能失败的方法。我喜欢它,但它非常“神奇”,光看它很难知道它的作用。我必须在心理上处理每一行才能“得到它”。 如果搜索到的字符串不存在,则会失败,而是错误地删除了最后一个字符。【参考方案5】:取决于您对 url 的了解以及您正在尝试做什么。如果您知道它将始终以“.com”(或“.net”或“.org”)结尾,那么
url=url[:-4]
是最快的解决方案。如果它是更通用的 URL,那么您可能最好查看 python 附带的 urlparse 库。
另一方面,如果您只想删除最后一个 '.' 之后的所有内容。然后在一个字符串中
url.rsplit('.',1)[0]
会起作用。或者,如果您只想要第一个 '.' 之前的所有内容。那就试试吧
url.split('.',1)[0]
【讨论】:
【参考方案6】:从Python 3.9
开始,您可以改用removesuffix
:
'abcdc.com'.removesuffix('.com')
# 'abcdc'
【讨论】:
规范中的python代码可以在PEP 616中找到【参考方案7】:如果你知道这是一个扩展,那么
url = 'abcdc.com'
...
url.rsplit('.', 1)[0] # split at '.', starting from the right, maximum 1 split
这同样适用于 abcdc.com
或 www.abcdc.com
或 abcdc.[anything]
并且更具可扩展性。
【讨论】:
【参考方案8】:任何 Python 版本:
def remove_suffix(text, suffix):
return text[:-len(suffix)] if text.endswith(suffix) and len(suffix) != 0 else text
Python 3.9+
text.removesuffix(suffix)
【讨论】:
或text[:-len(suffix)] if suffix and text.endswith(suffix) else text
【参考方案9】:
url[:-4]
怎么样?
【讨论】:
一旦你被.ca
或.co.uk
url 击中,似乎几乎肯定会导致错误。【参考方案10】:
对于 url(因为它似乎是给定示例主题的一部分),可以执行以下操作:
import os
url = 'http://www.***.com'
name,ext = os.path.splitext(url)
print (name, ext)
#Or:
ext = '.'+url.split('.')[-1]
name = url[:-len(ext)]
print (name, ext)
两者都会输出:
('http://www.***', '.com')
如果您只需要拆分“.com”或任何特定内容,也可以将其与 str.endswith(suffix)
结合使用。
【讨论】:
【参考方案11】:DSCLAIMER 此方法有一个严重缺陷,即分区未锚定到 url 的末尾,可能会返回虚假结果。例如,URL“www.comcast.net”的结果是“www”(不正确),而不是预期的“www.comcast.net”。因此,这个解决方案是邪恶的。除非您知道自己在做什么,否则不要使用它!
url.rpartition('.com')[0]
这很容易键入,并且当url
中缺少后缀“.com”时也可以正确返回原始字符串(无错误)。
【讨论】:
当只需要一个分割时首选+1分区,因为它总是返回答案,不会发生IndexError。 这不能正确处理不存在的后缀。例如,对于www.comcast.net
,它将错误地返回www
。
这是一个非常好的观点@Boris!非常感谢您指出这一点。【参考方案12】:
如果您只想剥离扩展名:
'.'.join('abcdc.com'.split('.')[:-1])
# 'abcdc'
它适用于任何扩展名,文件名中也可能存在其他点。它只是将字符串拆分为一个点列表,并在没有最后一个元素的情况下加入它。
【讨论】:
【参考方案13】:假设您要删除域,无论它是什么(.com、.net 等)。我建议找到 .
并从那时起删除所有内容。
url = 'abcdc.com'
dot_index = url.rfind('.')
url = url[:dot_index]
这里我使用rfind
来解决像abcdc.com.net
这样的url 应该简化为名称abcdc.com
的问题。
如果您还担心www.
s,您应该明确检查它们:
if url.startswith("www."):
url = url.replace("www.","", 1)
替换中的 1 用于奇怪的边缘情况,例如 www.net.www.com
如果您的网址比这更狂野,请查看人们回复的正则表达式答案。
【讨论】:
【参考方案14】:如果你需要删除一个字符串的某个结尾(如果它存在的话),否则什么也不做。我最好的解决方案。您可能希望使用前 2 个实现中的一个,但为了完整起见,我已包含第 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/
【讨论】:
【参考方案15】:因为这是一个非常受欢迎的问题,所以我添加了另一个现在可用的解决方案。使用 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[:]
以及它对自我实现的解决方案有什么好处:
不易碎: 该代码将不依赖于用户来计算文字的长度。
性能更高: 该代码不需要调用 Python 内置的 len 函数,也不需要调用更昂贵的 str.replace() 方法。
更具描述性: 与传统的字符串切片方法相比,这些方法为代码可读性提供了更高级别的 API。
【讨论】:
有人在您发布之前 8 个月就已经发布了此信息 ***.com/a/61432508【参考方案16】: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'
【讨论】:
【参考方案17】:就我而言,我需要引发异常,所以我这样做了:
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)]
【讨论】:
【参考方案18】:你可以使用拆分:
'abccomputer.com'.split('.com',1)[0]
# 'abccomputer'
【讨论】:
当a = 'www.computerbugs.com'
这个结果是'www
'【参考方案19】:
更广泛的解决方案,增加了替换后缀(您可以通过替换为空字符串来删除)和设置最大替换次数的可能性:: p>
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 '
【讨论】:
【参考方案20】:这是正则表达式的完美使用:
>>> import re
>>> re.match(r"(.*)\.com", "hello.com").group(1)
'hello'
【讨论】:
您还应该添加一个 $ 以确保您在“.com”中匹配结尾的主机名。【参考方案21】:这里,我有一个最简单的代码。
url=url.split(".")[0]
【讨论】:
【参考方案22】:Python >= 3.9:
'abcdc.com'.removesuffix('.com')
Python
def remove_suffix(text, suffix):
if text.endswith(suffix):
text = text[:-len(suffix)]
return text
remove_suffix('abcdc.com', '.com')
【讨论】:
您对 Python 3.9 的回答与上面的 this answer 重复。您对以前版本的回答也已在此线程中多次回答,如果字符串没有后缀,则不会返回任何内容。【参考方案23】:使用替换和计数
这可能看起来有点小技巧,但它可以确保您在不使用 startswith
和 if 语句的情况下进行安全替换,使用替换的 count
参数可以将替换限制为一个:
mystring = "www.comwww.com"
前缀:
print(mystring.replace("www.","",1))
后缀(你把前缀写反了).com
变成moc.
:
print(mystring[::-1].replace("moc.","",1)[::-1])
【讨论】:
【参考方案24】:我使用了内置的rstrip 函数,如下所示:
string = "test.com"
suffix = ".com"
newstring = string.rstrip(suffix)
print(newstring)
test
【讨论】:
坏主意。试试"test.ccom"
。
但这不是问题的重点。它只是被要求从另一个字符串的末尾删除一个已知的子字符串。这完全符合预期。
@Alex 使用 mooc.com 或 maximo.com 尝试您的解决方案
是的@lorenzo 我现在试过了,但它不能正常工作,因为它会吃掉所有东西。因此,尽管它适用于该示例,但它还不够通用。我尝试使用 split 并且效果更好,但仍然不完全通用:在 [13]: string = "testcom.cp.com" ...: suffix = ".com" ...: newstring = string.split(suffix) ...: print(newstring[0]) testcom.cp
您的回答表明了与提问者一样对strip
/rstrip
/lstrip
所做的事情的误解。他们将传递给他们的字符串视为 字符集 而不是要删除的文字后缀/前缀。请阅读the documentation。以上是关于如何从字符串末尾删除子字符串?的主要内容,如果未能解决你的问题,请参考以下文章