在Python中一次迭代String字

时间:2010-05-04 20:10:45

标签: python string string-matching

我有一个巨大的文本文件的字符串缓冲区。我必须在字符串缓冲区中搜索给定的单词/短语。什么是有效的方法呢?

我尝试使用re模块匹配。但由于我有一个巨大的文本语料库,我必须搜索。这需要花费大量时间。

给出单词和短语词典。

我遍历每个文件,将其读入字符串,搜索字典中的所有单词和短语,并在找到密钥时增加字典中的计数。

我们认为的一个小优化是将短语/单词的字典排序为最大字数。然后比较字符串缓冲区中的每个单词起始位置并比较单词列表。如果找到一个短语,我们不会搜索其他短语(因为它匹配最长的短语,这就是我们想要的)

有人可以建议如何在字符串缓冲区中逐字逐句。 (逐字迭代字符串缓冲区)?

此外,还有其他优化可以做到吗?

data = str(file_content)
for j in dictionary_entity.keys():
    cnt = data.count(j+" ")
    if cnt != -1:
        dictionary_entity[j] = dictionary_entity[j] + cnt
f.close()

8 个答案:

答案 0 :(得分:7)

通过文件的内容(在我的案例中来自Project Gutenberg的绿野仙踪)逐字逐句地进行迭代,有三种不同的方式:

from __future__ import with_statement
import time
import re
from cStringIO import StringIO

def word_iter_std(filename):
    start = time.time()
    with open(filename) as f:
        for line in f:
            for word in line.split():
                yield word
    print 'iter_std took %0.6f seconds' % (time.time() - start)

def word_iter_re(filename):
    start = time.time()
    with open(filename) as f:
        txt = f.read()
    for word in re.finditer('\w+', txt):
        yield word
    print 'iter_re took %0.6f seconds' % (time.time() - start)

def word_iter_stringio(filename):
    start = time.time()
    with open(filename) as f:
        io = StringIO(f.read())
    for line in io:
        for word in line.split():
            yield word
    print 'iter_io took %0.6f seconds' % (time.time() - start)

woo = '/tmp/woo.txt'

for word in word_iter_std(woo): pass
for word in word_iter_re(woo): pass
for word in word_iter_stringio(woo): pass

导致:

% python /tmp/junk.py
iter_std took 0.016321 seconds
iter_re took 0.028345 seconds
iter_io took 0.016230 seconds

答案 1 :(得分:1)

这听起来像trie真正有用的问题。您可能应该使用某种类似压缩的trie,如Patricia/radix trie。只要你能够在trie中找到你想要的整个单词/短语词典,这将大大减少时间复杂度。如何工作是你取一个单词的开头并下降trie直到找到最长的匹配并递增该节点中的计数器。这可能意味着如果部分匹配没有消失,你必须提升trie。然后你将进入下一个单词的开头并再次进行。 trie的优点在于,您通过trie搜索整个字典(每个查找应该占用O(m),其中m是字典中单词/短语的平均长度)。

如果你不能将整个字典整合成一个trie,那么你可以将字典分成几次尝试(一个用于所有以al开头的单词/短语,一个用于mz)并在整个过程中进行扫描每个特里的语料库。

答案 2 :(得分:0)

如果re模块无法快速完成,那么您将很难以更快的速度完成任务。无论哪种方式,您都需要读取整个文件。您可以考虑修复正则表达式(可以提供一个吗?)。也许还有一些关于你想要完成的事情的背景知识。

答案 3 :(得分:0)

你可以尝试反过来...而不是处理文本语料库2,000,000次(每个单词一次),只处理一次。对于语料库中的每个单词,递增哈希表或类似词以存储该词的计数。伪代码中的一个简单示例:

word_counts = new hash<string,int>
for each word in corpus:
  if exists(word_counts[word]):
    word_counts[word]++
  else:
    word_counts[word] = 1

您可以通过使用完整的单词列表提前初始化word_counts来加快速度,这不需要if语句......不确定。

答案 4 :(得分:0)

正如xyld所说,我不认为你可以超越re模块的速度,尽管如果你发布你的正则表达式以及可能的代码也会有所帮助。我可以添加的是在优化之前尝试分析。当您看到大部分处理过程时,您可能会感到非常惊讶。我使用hotshot来分析我的代码,我很满意。你可以在这里找到对python概要分析的一个很好的介绍http://onlamp.com/pub/a/python/2005/12/15/profiling.html

答案 5 :(得分:0)

如果使用re的性能不够,您可能正在使用findall(),或者手动逐个查找匹配项。使用迭代器可能会更快:

>>> for i in re.finditer(r'\w+', 'Hello, this is a sentence.'):
...     print i.group(0)
...     
Hello
this
is
a
sentence

答案 6 :(得分:0)

#!/usr/bin/env python
import re

s = ''
for i in xrange(0, 100000):
    s = s + 'Hello, this is a sentence. '
    if i == 50000:
        s = s + " my phrase "

s = s + 'AARRGH'

print len(s)

itr = re.compile(r'(my phrase)|(\w+)').finditer(s)
for w in itr:
    if w.group(0) == 'AARRGH':
        print 'Found AARRGH'
    elif w.group(0) == "my phrase":
        print 'Found "my phrase"'

运行这个,我们得到

$ time python itrword.py
2700017
Found "my phrase"
Found AARRGH

real    0m0.616s
user    0m0.573s
sys     0m0.033s

但是,明确添加到正则表达式中的每个“短语”都会对性能产生影响 - 通过粗略测量,上述速度比使用“\ w +”慢50%。

答案 7 :(得分:0)

您是否考虑过查看Natural Language Toolkit。它包含许多用于处理文本语料库的好函数,还有一个很酷的FreqDist类,它具有类似dict(有键)和类似列表(slice)的行为。