如果你需要删除一个字符串的某个结尾(如果它存在的话),否则什么也不做。我最好的解决方案。您可能希望使用前 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/