【问题标题】:Delete item from list if it contains a substring from a "blacklist"如果它包含来自“黑名单”的子字符串,则从列表中删除项目
【发布时间】:2014-11-14 14:51:17
【问题描述】:

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

例如,假设列表 A 如下:

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

列表 B 是:

B = ['XXX', 'BBB']

我如何获得列表 C:

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

我尝试过各种正则表达式和列表推导的组合,但我似乎无法让它发挥作用。

【问题讨论】:

  • 为什么要使用正则表达式?见this
  • 我很好奇那些在这个问题上加了Downvote的人!!!!!!!!!!!!!!!!!!!!!+1
  • 真棒的问题,我只是在找这个!

标签: python regex string list-comprehension


【解决方案1】:
>>> A = [ 'cat', 'doXXXg', 'monkey', 'hoBBBrse', 'fish', 'snake']
>>> B = ['XXX', 'BBB']

下面的列表理解将起作用

>>> [word for word in A if not any(bad in word for bad in B)]
['cat', 'monkey', 'fish', 'snake']

【讨论】:

  • 这个答案应该是公认的答案,因为它是一种更短、更 Pythonic 的解决 OP 问题的方法,并且不需要额外的模块。
【解决方案2】:

您可以将黑名单加入到一个表达式中:

import re

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

然后过滤掉匹配的单词:

C = [word for word in A if not blacklist.search(word)]

模式中的单词被转义(因此. 和其他元字符不被视为这样,而是被视为文字字符),并加入一系列| 替代项:

>>> '|'.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 个字符长)的列表,正则表达式的速度大约快 50%。

【讨论】:

  • 好吧,如果黑名单中早期匹配的可能性很高(或黑名单非常小),any() 测试可能会更快。始终根据您的实际情况进行合理建模!
  • 在我的情况下,黑名单只包含 10 个或更少的单词,但据说您提出的解决方案非常优雅。
  • @user1182556:用 10 个字我的解决方案已经更快了。 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-05
  • 2013-11-28
  • 2012-04-17
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多