特里?在python中匹配带尾随字符的单词

时间:2012-08-03 04:26:41

标签: python algorithm data-structures trie linguistics

这与stackoverflow上的大多数trie问题有点不同(是的,我花时间搜索和阅读),所以请耐心等待。

我有文件A,例如:allow *,apolog *等。总共有成千上万的这样的条目。我的文件B包含一个文本正文,最多可包含数千个单词。我希望能够将文件B中文本中的单词与文件A中的单词匹配。

示例:

文件B的“道歉”将与文件A的“道歉*”匹配

文件B的“a”既不匹配“allow *”也不匹配“apolog *”

文件B的“apologizetomenoworelseiwillkillyou”也会匹配文件A的“道歉*”

有人可以建议一个算法/数据结构(最好是在python中可以做到),这可以帮助我实现这个目标吗?我所研究的尝试似乎更多的是将前缀与整个单词匹配,但在这里,我将整个单词与前缀相匹配。词干算法是不可能的,因为它们有固定的规则,而在这种情况下我的后缀可以是任何东西。我不想在文件A中遍历我的整个列表,因为这会花费太多时间。

如果这令人困惑,我很乐意澄清。感谢。

4 个答案:

答案 0 :(得分:1)

将所有前缀放在哈希表中。然后取B中的每个单词并在哈希表中查找它的所有前缀。你得到的任何一击都表示匹配。

因此哈希表包含“allow”和“apolog”。对于“道歉”,你会查找“a”然后“ap”,依此类推,直到你查看“apolog”并找到匹配。

答案 1 :(得分:1)

如果我理解您要查找的内容,您希望能够看到文件A中与文件B中给定的完整单词匹配的所有前缀.Trie数据结构允许您将单个前缀与列表相匹配完整的话,但你需要走另一个方向。

如果是这样,您仍然可以使用trie进行匹配,使用查找表来反转结果。这是算法:

  • 迭代文件B中的单词,将它们放入trie。
  • 迭代文件A中的前缀,从trie中找到匹配项。
    • 对于每个匹配,将前缀添加到列表字典中,并按匹配的单词索引。

这是实现该算法的一些代码。你需要名为Trie的trie类和作为参数wordsprefixes传入的iterables(如果你不希望值同时存在于内存中,则使用生成器):

def matchPrefixes(words, prefixes):
    """Returns a word-to-prefix lookup table."""

    trie = Trie()
    for word in words:
        trie.add(word)

    lookupTable = defaultdict(list)
    for prefix in prefixes:
        matchedWords = trie.matchPrefix(prefix)

        for word in matchedWords:
            lookupTable[word].append(prefix)

    return lookupTable

这在时间和内存方面应该非常有效,特别是当单词列表比前缀列表短得多时。与任何单词不匹配的前缀在针对trie进行检查后将不会使用任何内存。

答案 2 :(得分:1)

如果文件B中的单词数远大于文件A中的前缀,您还可以构建前缀的Trie并匹配其中的单词。

如果您了解Trie的工作方式会更容易。 Trie是一个由字符串构建的树,如下所示。匹配Trie中的字符串是从根到其中一个叶子的过程。

在你的问题中,如果我们将前缀放在Trie中,并查找单词,我们需要将Trie中的一些内部节点标记为前缀的终止。当我们在Trie中查找单词时,每当我们到达标记为前缀终止的节点时,我们将该前缀添加为单词“匹配”。 (然后我们继续写下一封信)。

这正是@ Blckknght解决方案的逆转解决方案。哪个更有效取决于文件A和文件B中的哪一个更大。

在@ Blckknght的解决方案中,Trie中的每个节点都由一组单词(其路径)包含节点标记。搜索前缀以前缀的最后一个字母结束。当它停止时,我们采用搜索停止的Trie节点,然后我们添加节点上标记的与前缀匹配的集合。

如果对任何人都有帮助,我会写一些伪造的代码。

Trie from wiki, from which you can find some code in "Algorithms" part

enter image description here

答案 3 :(得分:1)

假设每个文件中有100,000个单词。

排序= n * log(n) 二进制搜索查找= log(n)

所以这是更糟糕的情况n * log(n)

这是100,000 * log(100,000)= 100,000 * 11 = 10 ^ 6 =几乎是瞬间

我认为你不需要这些小文件。简单地排序和二元搜索:

__author__ = 'Robert'

from bisect import bisect_right

file_a = """hell*
wor*
howard*
are*
yo*
all*
to*""".splitlines()

file_b = """hello world how are you all today too told town""".split()

a_starts = sorted(word[:-1] for word in file_a) #can do this easily if only 100, 000 words as you say.

def match(word):
    pos = bisect_right(a_starts, word)
    #assert 0 <= pos < len(a_starts)
    matched_word = a_starts[pos - 1]
    return matched_word if word.startswith(matched_word) else None

for word in file_b:
    print(word, " -> ", match(word))

"""
hello  ->  hell
world  ->  wor
how  ->  None
are  ->  are
you  ->  yo
all  ->  all
today  ->  to
too  ->  to
told  ->  to
town  ->  to
"""