在Python中从列表中查找字符串的精确匹配

1 投票
2 回答
3068 浏览
提问于 2025-04-17 20:53

我正在做一个项目,这个项目会从我关注的人中搜索特定用户的推特动态,并转发它们。下面的代码运行得很好,但如果要找的字符串出现在单词的中间,比如我想找“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 个回答

1

如果你想用正则表达式来实现这个功能,可以寻找一个这样的模式:\b<字符串>\b。在你的情况下,这个模式就是:

pattern = re.compile(r"\bman\b")
if re.search(pattern, tweet["text"].lower()):
    #do your thing 

\b 在正则表达式中表示一个单词的边界。所以在你的模式前后加上这个,就只会匹配这个特定的模式。希望这对你有帮助。

3

因为你只想匹配完整的单词,所以让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)

撰写回答