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