在Python中从列表中查找字符串的精确匹配
我正在做一个项目,这个项目会从我关注的人中搜索特定用户的推特动态,并转发它们。下面的代码运行得很好,但如果要找的字符串出现在单词的中间,比如我想找“man”,但有人写成“manager”,那么它也会被转发。我对Python还不太熟悉,但我觉得正则表达式可能是解决这个问题的好方法,不过到目前为止我尝试的都没有成功。
if tweet["user"]["screen_name"] in friends:
for phrase in list:
if phrase in tweet["text"].lower():
print tweet
api.retweet(tweet["id"])
return True
2 个回答
如果你想用正则表达式来实现这个功能,可以寻找一个这样的模式:\b<字符串>\b
。在你的情况下,这个模式就是:
pattern = re.compile(r"\bman\b")
if re.search(pattern, tweet["text"].lower()):
#do your thing
\b
在正则表达式中表示一个单词的边界。所以在你的模式前后加上这个,就只会匹配这个特定的模式。希望这对你有帮助。
因为你只想匹配完整的单词,所以让Python做到这一点最简单的方法就是把推文的文本分割成一个单词列表,然后用 in
来检查每个单词是否存在。
这里有一个优化的方法,因为位置并不重要:通过从单词列表构建一个集合,你可以让搜索变得更快(技术上讲,速度从 O(n) 提升到 O(1)),这是因为集合和字典使用了快速的哈希访问(感谢 Tim Peters,他也是《Python之禅》的作者)。
完整的解决方案是:
if tweet["user"]["screen_name"] in friends:
tweet_words = set(tweet["text"].lower().split())
for phrase in list:
if phrase in tweet_words:
print tweet
api.retweet(tweet["id"])
return True
这并不是一个完整的解决方案。实际上,你还应该处理一下开头和结尾的标点符号。你可以写一个函数来处理这些,然后用推文文本作为参数来调用它,而不是直接使用 .split()
方法。
考虑到这个优化,我想到如果短语也是一个集合,就可以完全避免在Python中进行迭代(虽然迭代仍然会发生,但速度会比Python快得多)。所以在接下来的代码中,假设你在初始化时执行了以下代码:
tweet_words = set(l.lower() for l in list)
顺便说一下,list
这个变量名实在是太糟糕了,因为使用它会让Python的列表类型在通常的名称下不可用(不过你仍然可以用一些技巧,比如 type([])
来访问它)。也许叫它 word_list
或者其他更有意义且不与现有名称冲突的名字会更好。你需要根据自己的需求调整这段代码,这只是给你一个思路。注意 tweet_words
只需要设置一次。
list = ['Python', 'Perl', 'COBOL']
tweets = [
"This vacation just isn't worth the bother",
"Goodness me she's a great Perl programmer",
"This one slides by under the radar",
"I used to program COBOL but I'm all right now",
"A visit to the doctor is not reported"
]
tweet_words = set(w.lower() for w in list)
for tweet in tweets:
if set(tweet.lower().split()) & tweet_words:
print(tweet)