Python文本搜索问题

时间:2011-09-22 16:31:05

标签: python

我想知道,如果你用Python打开一个文本文件。然后你想搜索包含许多字母的单词。

假设您输入要搜索的6个不同字母(a,b,c,d,e,f)。 你想找到至少3个字母的单词。 每个字母只能出现一个单词。 字母'a'总是必须包含。

对于这种特定类型的搜索,代码应该如何?

4 个答案:

答案 0 :(得分:3)

让我们看看......

return [x for x in document.split()
        if 'a' in x and sum((1 if y in 'abcdef' else 0 for y in x)) >= 3]
没有参数的

split充当"字"函数,拆分任何空格并删除不包含字符的单词。然后你检查字母' a'在这个词里面。如果' a'在单词中,您使用生成器表达式,该表达式遍历单词中的每个字母。如果字母在可用字母串内,则返回1,该值对总和有贡献。否则,它返回0.然后如果总和是3或更大,它保持它。使用生成器而不是列表推导,因为sum将接受任何可迭代的内容,并且它会阻止必须创建临时列表(减少内存开销)。

由于使用in(在字符串上应该有O(n)时间),它没有最佳的访问时间,但这通常不是一个很大的问题除非数据集很大。您可以优化一点,将字符串打包成一个集合,并且常量' abcdef'很容易就成了一套。我只是不想破坏漂亮的衬垫。

编辑:哦,为了改善if部分(效率低下的部分)的时间,你可以把它分成一个迭代字符串一次的函数,如果符合条件就返回True 。我会这样做,但它毁了我的一个班轮。

编辑2:我没有看到"必须有3个不同的角色"部分。你不能在一个班轮里做到这一点。你可以把if部分带到一个函数中。

def is_valid(word, chars):
    count = 0
    for x in word:
        if x in chars:
            count += 1
            chars.remove(x)
    return count >= 3 and 'a' not in chars

def parse_document(document):
    return [x for x in document.split() if is_valid(x, set('abcdef'))]

这个在现实世界的数据集上不应该有任何性能问题。

答案 1 :(得分:2)

如果我不得不写这个,我会怎么做:

我有一个函数,给定一个单词,将检查它是否满足条件并返回一个布尔标志。

然后我会有一些代码会迭代文件中的所有单词,将每个单词显示给函数,并打印出函数返回的那些单词True

答案 2 :(得分:0)

words = 'fubar cadre obsequious xray'

def find_words(src, required=[], letters=[], min_match=3):
    required = set(required)
    letters = set(letters)

    words = ((word, set(word)) for word in src.split())
    words = (word for word in words if word[1].issuperset(required))
    words = (word for word in words if len(word[1].intersection(letters)) >= min_match)
    words = (word[0] for word in words)
    return words

w = find_words(words, required=['a'], letters=['a', 'b', 'c', 'd', 'e', 'f'])
print list(w)

编辑1:我也没有仔细阅读这些要求。确保单词仅包含1个有效字母的实例。

from collections import Counter

def valid(word, letters, min_match):
    """At least min_match, no more than one of any letter"""
    c = 0
    count = Counter(word)
    for letter in letters:
        char_count = count.get(letter, 0)
        if char_count > 1:
            return False
        elif char_count == 1:
            c += 1
        if c == min_match:
            return True
    return True


def find_words(srcfile, required=[], letters=[], min_match=3):
    required = set(required)
    words = (word for word in srcfile.split())
    words = (word for word in words if set(word).issuperset(required))
    words = (word for word in words if valid(word, letters, min_match))
    return words

答案 3 :(得分:0)

我同意aix的总体计划,但它可能比“设计模式”更为普遍,而且我不确定它会给你带来多大的影响,因为它归结为“,找出一种方法来检查是什么你想找到然后检查你需要检查的一切。“

有关如何找到您想要找到的内容的建议:您已经进入了算法研究的最基本领域之一。虽然LCS(最长公共子串)被更好地覆盖,但你也可以找到遏制的好例子。我见过的关于这个主题的最严格的讨论是在Google cs wonk的网站上:http://neil.fraser.name。他有一个名为diff-match-patch的东西,它以许多不同的语言发布和优化,包括python,可以在这里下载: http://code.google.com/p/google-diff-match-patch/

如果你想更多地了解python和算法,magnus hetland写了一本关于python算法的好书,他的网站在字符串匹配和模糊字符串匹配等方面有一些例子,包括levenshtein距离简单易懂的格式。 (google for magnus hetland,我不记得地址)。

在标准库中,您可以查看difflib,它提供了许多方法来评估字符串的相似性。你正在寻找不相同的遏制,但它是非常相关的,你可能会根据你的需要制作一组你可以比较的候选词。

或者你可以使用python,Counter的新增功能,并将你正在测试的单词重建为字符串列表,然后为每个测试字母创建一个需要1或更多计数的函数。

最后,关于aix方法的第二部分,'然后将它应用于你想要测试的所有内容,'我建议你看一下itertools。如果你有任何效率约束,你将需要使用生成器和aix提出的测试可以使用itertools.ifilter在python中最有效地执行。您的函数对于要保留的值以及内置函数bool返回True。所以你可以做itertools.ifilter(bool,test_iterable),它将返回所有成功的值。

祝你好运