这是我目前的情况:
最后一点是问题所在。实际上我需要搜索完全匹配和字符串的部分匹配。我写的算法只涉及使用正则表达式结合一些尝试来使进程更快:例如,我将字典的索引硬编码到我的脚本中,识别字母表的单数字母,然后拆分大文本文件fictionary成26个较小的字典。 这完全没用,脚本仍然非常慢。 在这里略读一些帖子,我确信尝试了mmap:但是在给定正则表达式的情况下找到所有部分匹配似乎没用。 最后我得出结论,特里可以解决我的问题,虽然我几乎不知道这是什么。我应该尝试一下吗?如果是这样,我应该如何继续在python中创建一个trie? Is marisa-trie module good?感谢大家
编辑:通过“部分匹配”,我的意思是我有一个字符串的前缀。我不需要在结尾或中间进行比赛,只是在比赛开始时。
答案 0 :(得分:5)
最简单,最快速的解决方案:
#!/usr/bin/env python
d = {}
# open your file here, i'm using /etc/hosts as an example...
f = open("/etc/hosts","r")
for line in f:
line = line.rstrip()
l = len(line)+1
for i in xrange(1,l):
d[line[:i]] = True
f.close()
while True:
w = raw_input('> ')
if not w:
break
if w in d:
print "match found", w
这稍微复杂一点,但内存效率高:
#!/usr/bin/env python
d = []
def binary_search(a, x, lo=0, hi=None):
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
midval = a[mid]
if midval < x:
lo = mid+1
elif midval > x:
hi = mid
else:
return mid
return -1
f = open("/etc/hosts","r")
for line in f:
line=line.rstrip()
l = len(line)+1
for i in xrange(1,l):
x = hash(line[:i])
d.append(x)
f.close()
d.sort()
while True:
w = raw_input('> ')
if not w:
break
if binary_search(d, hash(w)) != -1:
print "match found", w
答案 1 :(得分:2)
由于文件已经被排序和读入,因此您可以在其上使用二进制搜索,而无需借助任何奇特的数据结构。 Python有一个内置的二进制搜索功能,bisect.bisect_left`。
答案 2 :(得分:1)
使用trie。
#dictionary is a list of words
def parse_dictionary(dictionary):
dictionary_trie = {}
for word in dictionary:
tmp_trie = dictionary_trie
for letter in word:
if letter not in tmp_trie:
tmp_trie[letter] = {}
if 'words' not in tmp_trie[letter]:
tmp_trie[letter]['words'] = []
tmp_trie[letter]['words'].append(word)
tmp_trie = tmp_trie[letter]
return dictionary_trie
def matches(substring, trie):
d = trie
for letter in substring:
try:
d = d[letter]
except KeyError:
return []
return d['words']
用法示例:
>>> import pprint
>>> dictionary = ['test', 'testing', 'hello', 'world', 'hai']
>>> trie = parse_dictionary(dictionary)
>>> pprint.pprint(trie)
{'h': {'a': {'i': {'words': ['hai']}, 'words': ['hai']},
'e': {'l': {'l': {'o': {'words': ['hello']}, 'words': ['hello']},
'words': ['hello']},
'words': ['hello']},
'words': ['hello', 'hai']},
't': {'e': {'s': {'t': {'i': {'n': {'g': {'words': ['testing']},
'words': ['testing']},
'words': ['testing']},
'words': ['test', 'testing']},
'words': ['test', 'testing']},
'words': ['test', 'testing']},
'words': ['test', 'testing']},
'w': {'o': {'r': {'l': {'d': {'words': ['world']}, 'words': ['world']},
'words': ['world']},
'words': ['world']},
'words': ['world']}}
>>> matches('h', trie)
['hello', 'hai']
>>> matches('he', trie)
['hello']
>>> matches('asd', trie)
[]
>>> matches('test', trie)
['test', 'testing']
>>>
答案 3 :(得分:0)
您可以创建一个列表,让每一行成为列表中的一个元素并进行二分查找。
答案 4 :(得分:0)
使用trie仍然需要你构建一个trie,它是O(n)迭代整个文件 - 利用排序会使它成为O(log_2 n)。因此,这种更快的解决方案将使用二进制搜索(见下文)。
此解决方案仍需要您读入整个文件。在更快的解决方案中,您可以预处理文件并填充所有行,使它们具有相同的长度(或在文件中构建某种索引结构,以便在列表中间寻找可行) - - 然后寻找文件的中间位置会将您带到列表的中间位置。 “更快”的解决方案可能只需要一个非常非常大的文件(千兆字节或几百兆字节)。你可以将它与二进制搜索结合起来。
可能,如果文件系统支持sparse files - 执行上述填充方案将不会增加磁盘上使用的文件实际块。
然后,在那时,您可能正在接近b树或b +树实现,以使索引有效。所以你可以使用b-tree library。
这样的事情:
import bisect
entries = ["a", "b", "c", "cc", "cd", "ce", "d", "e", "f" ]
def find_matches(ls, m):
x = len(ls) / 2
match_index = -1
index = bisect.bisect_left(ls, m)
matches = []
while ls[index].startswith(m):
matches.append(ls[index])
index += 1
return matches
print find_matches(entries, "c")
输出:
>>> ['c', 'cc', 'cd', 'ce']
答案 5 :(得分:0)
因此,为了解释arainchi非常好的答案,请为您的文件中的每一行创建一个带有条目的字典。然后,您可以将搜索字符串与这些条目的名称进行匹配。字典对于这种搜索非常方便。