使用正则表达式循环的更有效方法是什么?

Chr*_*ong 0 python regex list

我有一个名单列表,我用它来提取目标字符串列表.例如:

names = ['Chris', 'Jack', 'Kim']
target = ['Chris Smith', 'I hijacked this thread', 'Kim','Christmas is here', 'CHRIS']

output = ['Chris Smith', 'Kim', 'CHRIS']
Run Code Online (Sandbox Code Playgroud)

所以到目前为止的规则是:

  • 不区分大小写
  • 无法匹配部分单词('即圣诞节/劫持不应与克里斯/杰克相匹配)
  • 只要在符合上述标准的字符串中找到名称,字符串中的其他单词就可以了.

为此,另一个SO用户在此主题中建议了此代码:

[targ for targ in target_list if any(re.search(r'\b{}\b'.format(name), targ, re.I) for name in first_names)]
Run Code Online (Sandbox Code Playgroud)

到目前为止,这非常准确,但非常缓慢,因为名称列表长度约为5,000,目标列表长度为20-100行,一些字符串长度不超过30个字符.

有关如何提高性能的任何建议吗?

解决方案:两个基于正则表达式的解决方案都遇到了OverflowErrors,所以遗憾的是我无法测试它们.有效的解决方案(来自@ mglison的回答)是:

new_names = set(name.lower() for name in names)
[ t for t in target if any(map(new_names.__contains__,t.lower().split())) ]
Run Code Online (Sandbox Code Playgroud)

这使得性能从15秒大幅提升到1秒以下.

mgi*_*son 5

好像你可以将它们全部组合成1个超级正则表达式:

import re

names = ['Chris', 'Jack', 'Kim']
target = ['Chris Smith', 'I hijacked this thread', 'Kim','Christmas is here', 'CHRIS']

regex_string = '|'.join(r"(?:\b"+re.escape(x)+r"\b)" for x in names)
print regex_string
regex = re.compile(regex_string,re.I)
print [t for t in target if regex.search(t)]
Run Code Online (Sandbox Code Playgroud)

非正则表达式解决方案,只有在名称是单个单词(无空格)时才有效:

new_names = set(name.lower() for name in names)
[ t for t in target if any(map(new_names.__contains__,t.lower().split())) ]
Run Code Online (Sandbox Code Playgroud)

any表达式也可以写为:

any(x in new_names for x in t.lower().split())
Run Code Online (Sandbox Code Playgroud)

要么

any(x.lower() in new_names for x in t.split())
Run Code Online (Sandbox Code Playgroud)

或者,另一个依赖的变体set.intersection(由以下@DSM建议):

[ t for t in target if new_names.intersection(t.lower().split()) ]
Run Code Online (Sandbox Code Playgroud)

如果性能非常关键,您可以剖析以查看哪个性能最佳,否则请选择您认为最容易阅读/理解的那个.

*如果你正在使用python2.x,你可能会想要使用itertools.imap而不是map如果你在上面的那条路上去懒惰地评估它 - 它也让我想知道python是否提供了一个懒惰的str.split性能与非懒惰版本相提并论......