Python中从字符串中删除多个字符串的最佳方法

7

Python 3.6

我想从一个字符串中删除一组字符串。这是我的第一次尝试:

string = 'this is a test string'
items_to_remove = ['this', 'is', 'a', 'string']
result = list(filter(lambda x: x not in items_to_remove, string.split(' ')))
print(result)

输出:

['test']

但是如果x的间距不好,这种方法就行不通。我感觉肯定有内置的解决方案,嗯,一定有更好的方法!

我看了一下这个discussion在stack overflow上的讨论,问题和我的完全一样...

为了不浪费我的努力,我计时了所有的解决方案。我相信最简单、最快速、最pythonic的方法是简单的for循环。这与其他帖子中的结论不同...

result = string
for i in items_to_remove:
    result = result.replace(i,'')

测试代码:

import timeit

t1 = timeit.timeit('''
string = 'this is a test string'
items_to_remove = ['this', 'is', 'a', 'string']
result = list(filter(lambda x: x not in items_to_remove, string.split(' ')))
''', number=1000000)
print(t1)

t2 = timeit.timeit('''
string = 'this is a test string'
items_to_remove = ['this', 'is', 'a', 'string']
def sub(m):
    return '' if m.group() in items_to_remove else m.group()

result = re.sub(r'\w+', sub, string)
''',setup= 'import re', number=1000000)
print(t2)

t3 = timeit.timeit('''
string = 'this is a test string'
items_to_remove = ['this', 'is', 'a', 'string']
result = re.sub(r'|'.join(items_to_remove), '', string)
''',setup= 'import re', number=1000000)
print(t3)

t4 = timeit.timeit('''
string = 'this is a test string'
items_to_remove = ['this', 'is', 'a', 'string']
result = string
for i in items_to_remove:
    result = result.replace(i,'')
''', number=1000000)
print(t4)

输出:

1.9832003884248448
4.408749988641971
2.124719851741177
1.085117268194475

1
这些解决方案之间存在差异 - 有些会考虑完整的单词,而另一些(例如for循环)也会替换子字符串。尝试更改items_to_remove的顺序为:['is','this','a','string'],你就会明白我在说什么了。 - zwer
哦,那是一个很好的观点! - James Schinner
1个回答

6

如果您对字符串间距不确定,可以使用 string.split()

string.split()string.split(' ') 有一些不同之处:

In [128]: 'this     is   a test'.split()
Out[128]: ['this', 'is', 'a', 'test']

In [129]: 'this     is   a test'.split(' ')
Out[129]: ['this', '', '', '', '', 'is', '', '', 'a', 'test']

前者可以在不产生多余空字符串的情况下分割字符串。

如果你想要更安全一点,或者你的字符串可能包含制表符和换行符,那么使用正则表达式是另外一种解决方案:

In [131]: re.split('[\s]+',  'this     is \t  a\ntest', re.M)
Out[131]: ['this', 'is', 'a', 'test']

最后,我建议将您的查找列表转换为查找set以便在过滤器中进行高效查找:
In [135]: list(filter(lambda x: x not in {'is', 'this', 'a', 'string'}, string.split()))
Out[135]: ['test']

谈到性能问题时,列表推导式比过滤器略快一些,虽然写法不够简洁:

In [136]: [x for x in string.split() if x not in {'is', 'this', 'a', 'string'}]
Out[136]: ['test']

这很有价值,有几个微妙的事情我没有考虑到。 - James Schinner

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