从列表中删除包含“黑名单”子字符串的项

2024-03-28 16:25:15 发布

您现在位置:Python中文网/ 问答频道 /正文

在python中,我希望从一个列表中删除包含在所谓的“黑名单”中找到的子字符串的任何字符串。在

例如,假设列表A如下:

A = [ 'cat', 'doXXXg', 'monkey', 'hoBBBrse', 'fish', 'snake']

列表B是:

^{pr2}$

我怎样才能得到清单C:

C = [ 'cat', 'monkey', 'fish', 'snake']

我尝试过各种regex表达式和列表理解的组合,但似乎无法使其发挥作用。在


Tags: 字符串列表表达式regexcatmonkeysnakefish
2条回答
>>> A = [ 'cat', 'doXXXg', 'monkey', 'hoBBBrse', 'fish', 'snake']
>>> B = ['XXX', 'BBB']

下面的列表理解将起作用

^{pr2}$

您可以将黑名单合并为一个表达式:

import re

blacklist = re.compile('|'.join([re.escape(word) for word in B]))

然后过滤掉匹配的单词:

^{pr2}$

模式中的单词被转义(因此.和其他元字符不被视为原语字符,而是作为字面字符处理),并被连接到一系列|备选方案中:

>>> '|'.join([re.escape(word) for word in B])
'XXX|BBB'

演示:

>>> import re
>>> A = [ 'cat', 'doXXXg', 'monkey', 'hoBBBrse', 'fish', 'snake']
>>> B = ['XXX', 'BBB']
>>> blacklist = re.compile('|'.join([re.escape(word) for word in B]))
>>> [word for word in A if not blacklist.search(word)]
['cat', 'monkey', 'fish', 'snake']

这应该优于任何明确的成员资格测试,尤其是随着黑名单中单词数量的增加:

>>> import string, random, timeit
>>> def regex_filter(words, blacklist):
...     [word for word in A if not blacklist.search(word)]
... 
>>> def any_filter(words, blacklist):
...     [word for word in A if not any(bad in word for bad in B)]
... 
>>> words = [''.join([random.choice(string.letters) for _ in range(random.randint(3, 20))])
...          for _ in range(1000)]
>>> blacklist = [''.join([random.choice(string.letters) for _ in range(random.randint(2, 5))])
...              for _ in range(10)]
>>> timeit.timeit('any_filter(words, blacklist)', 'from __main__ import any_filter, words, blacklist', number=100000)
0.36232495307922363
>>> timeit.timeit('regex_filter(words, blacklist)', "from __main__ import re, regex_filter, words, blacklist; blacklist = re.compile('|'.join([re.escape(word) for word in blacklist]))", number=100000)
0.2499098777770996

上面测试了10个随机黑名单的短单词(2-5个字符)和1000个随机单词(3-20个字符长)的对比,regex大约快50%。在

相关问题 更多 >