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

崔?在python中匹配带尾随字符的单词,python,algorithm,data-structures,trie,linguistics,Python,Algorithm,Data Structures,Trie,Linguistics,这与stackoverflow上的大多数trie问题有点不同(是的,我花了时间搜索和阅读),所以请耐心听我说 我有一个文件,里面有:allow*、apolog*等词。这样的条目总共有上万条。我有一个文件B,其中包含一个正文,最多有数千个单词。我希望能够将文件B中文本中的单词与文件A中的单词进行匹配 例如: 文件B的“道歉”与文件A的“道歉” 文件B的“a”与“allow*”和“apolog*”都不匹配 文件B的“道歉”也将与文件A的“道歉*”匹配 有谁能建议一种算法/数据结构(最好是python

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

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

例如:

文件B的“道歉”与文件A的“道歉”

文件B的“a”与“allow*”和“apolog*”都不匹配

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


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


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

将所有前缀放在哈希表中。然后把B中的每个单词都取出来,在哈希表中查找它的所有前缀。你得到的任何一击都表明是一场比赛


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

将所有前缀放入哈希表中。然后把B中的每个单词都取出来,在哈希表中查找它的所有前缀。你得到的任何一击都表明是一场比赛


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

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

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

  • 迭代文件B中的单词,将它们放入trie中
  • 迭代文件A中的前缀,从trie中查找匹配项。
    • 对于每个匹配项,将前缀添加到列表字典中,由匹配的单词索引
下面是一些实现算法的代码。您需要名为
trie
的trie类和作为参数
words
prefixes
传入的iterables(如果不希望所有值同时在内存中,请使用生成器):


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

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

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

  • 迭代文件B中的单词,将它们放入trie中
  • 迭代文件A中的前缀,从trie中查找匹配项。
    • 对于每个匹配项,将前缀添加到列表字典中,由匹配的单词索引
下面是一些实现算法的代码。您需要名为
trie
的trie类和作为参数
words
prefixes
传入的iterables(如果不希望所有值同时在内存中,请使用生成器):


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

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

如果您了解Trie的工作方式,这将容易得多。Trie是从字符串构建的树,如下所示。在Trie中匹配字符串是一个从根到一片叶子的过程

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

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

在@Blckknght的解决方案中,Trie中的每个节点都由包含该节点的单词集(其路径)进行标记。前缀的搜索在前缀的最后一个字母处结束。当它停止时,我们获取搜索停止的Trie节点,然后将节点上标记为匹配前缀的集合添加到前缀中

如果对任何人都有帮助的话,我会写一些pesudo代码


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

如果您了解Trie的工作方式,这将容易得多。Trie是从字符串构建的树,如下所示。在Trie中匹配字符串是一个从根到一片叶子的过程

在您的问题中,如果我们将前缀放在Trie中并查找单词,则需要标记一些内部节点
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
__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
"""