我有一个名单列表,我试图从字符串列表中提取出来。我不断得到部分匹配等误报。另一个需要注意的是,我希望在适用的情况下也可以使用姓氏。
names = ['Chris', 'Jack', 'Kim']
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS']
desired_output = ['Chris Smith', 'Kimberly', 'CHRIS']
我试过这段代码:
[i for e in names for i in target if i.startswith(e)]
这可以预见地回归克里斯史密斯,圣诞节就在这里,还有金伯利。
我最好如何处理这个问题?使用正则表达式还是可以使用列表推导完成?性能可能是一个问题,因为真实姓名列表的名称长度约为880,000。
(python 2.7)
编辑:我已经意识到我在这个例子中的标准是不切实际的,因为在排除圣诞节时想要包括金伯利的不可能的要求就在这里。为了缓解这个问题,我找到了一个更完整的名单,其中包括变体(包括Kim和Kimberly)。
答案 0 :(得分:1)
完全猜测(再次)因为我看不出你如何给出Christmas is here
任何合理的标准:
这将匹配任何包含任何以单词名称开头的单词的目标...
names = ['Chris', 'Jack', 'Kim']
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS']
import re
matches = [targ for targ in target if any(re.search(r'\b{}'.format(name), targ, re.I) for name in names)]
print matches
# ['Chris Smith', 'Kimberly', 'Christmas is here', 'CHRIS']
如果您将其更改为\b{}\b' - then you'll get ['Chris Smith', 'CHRIS']
,那么您将失去Kim
...
答案 1 :(得分:0)
这有用吗?
names = ['Chris', 'Jack', 'Kim']
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS']
res = []
for tof in target:
for name in names:
if tof.lower().startswith(name.lower()):
res.append(tof)
break
print res
答案 2 :(得分:0)
没有确定的方法来放弃比赛'圣诞节在这里',因为系统可能无法确定圣诞节是名字还是其他东西。 相反,如果你想加快这个过程,你可以尝试这种O(n)方法。 我还没有计时,但肯定比你或者提议的解决方案更快。
from difflib import SequenceMatcher
names = ['Chris', 'Jack', 'Kim']
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS']
def foo(names, target):
#Create a generator to search the names
def bar(names, target):
#which for each target
for t in target:
#finds the matching blocks, a triplet, (i, j, n), and means that a[i:i+n] == b[j:j+n]
match = SequenceMatcher(None,names, t).get_matching_blocks()[0]
#match.size == 0 means no match
#and match.b > 0 means match does not happens at the start
if match.size > 0 and match.b == 0:
#and generate the matching target
yield t
#Join the names to create a single string
names = ','.join(names)
#and call the generator and return a list of the resultant generator
return list(bar(names, target))
>>> foo(names, target)
['Chris Smith', 'Kimberly', 'Christmas is here', 'CHRIS']
答案 3 :(得分:0)
根据你的描述,我得到的规则是:
试试这个:
names = ['Chris', 'Jack', 'Kim']
target = ['Chris Smith', 'I hijacked this thread', 'Kimberly','Christmas is here', 'CHRIS']
desired_output = ['Chris Smith', 'Kimberly', 'CHRIS']
actual_output = []
for key in names:
for words in target:
for word in words.split():
if key.lower() == word.lower():
actual_output.append(words)
elif key.lower() == word.lower()[:len(key)] and len(words.split()) == 1:
actual_output.append(words)
print(actual_output)
它将输出完全作为您想要的输出(顺便说一下,你确定你真的想要这个吗?)。不要被3层循环挫败。如果您有N个名字和M个句子,并且每个句子中的单词数量有限,那么此代码的复杂性为O(mn)
,这是不可能更好的。