2012-12-16 144 views
-1

我有一列名字,我试图从字符串列表中取出。我一直得到误判,如部分匹配。另一个警告是,我希望它也可以在适用的情况下获取姓氏。基于另一个列表中的值搜索列表

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)] 

这不出所料返回克里斯·史密斯,圣诞节是在这里,和金佰利。

我该如何做到最好?使用正则表达式还是可以用列表解析来完成?性能可能是一个问题,因为实名名单长约88万个名字。

(Python 2.7版)

编辑:我已经意识到我在这个例子中的标准是不现实的因为想包括金佰利同时排除圣诞节是这里的不可能的要求。为了缓解这个问题,我发现了一个更完整的名单,其中将包括变体(包括Kim和Kimberly)。

+4

为什么'CHRIS'出现在输出中,而不是'我劫持了这个线程'? –

+0

到目前为止您尝试了哪些方法? –

+0

如果输入''Kimberly'',那么为什么'圣诞节在这里'缺失? –

回答

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 ...

+0

这似乎是最紧凑和最优雅的解决方案。根据我根据我的OP中的编辑更改的标准,我只是在搜索模式的末尾添加了另一个\ b – ChrisArmstrong

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 
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'] 
0

根据你的描述,我得到的规则是:

  1. 忽略的情况;
  2. 目标单词必须以关键字开头。
  3. 如果目标单词不完全是关键词,那么目标单词必须是句子中唯一的单词。

试试这个:

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) 

它将输出EXACTLY为所需输出(顺便说一句,你确定你真的想要吗?)。不要因三层环路而感到沮丧。如果你有N个名字和M个句子,并且每个句子中的单词数量是有限的,那么这个代码的复杂性是O(mn),这不可能是更好的。

相关问题