针对长表达式列表优化正则表达式匹配

时间:2016-11-03 14:16:43

标签: python regex algorithm string-matching

问题定义:给定长度为n个字符的文本和长度为t的术语列表(可能是正则表达式),找到并计算文本中所有出现的术语。< / p>

这是一个天真的实现:

class WordFrequency(TextAnalysis):
    """Determines the frequency of words from a vocabulary in a given text"""

    def __init__(self, vocabulary, text):
        """
        :param vocabulary: contains the words (e.g. list)
        :param text: the analysed text
        """
        self.text = text
        self.vocabulary = vocabulary
        self.matches = {}

    def run(self):
        """
        :return: self for method chaining
        """

        ltext = self.text.lower()
        self.freq = {} # word -> absolute frequency
        for word in self.vocabulary:
            matches = re.findall(r'\b' + word + r'\b', ltext)
            self.matches[word] = [match for match in matches]  #.lstrip() for match in matches]
            self.freq[word] = len(matches)
        return self

现在,对于长度为ca的文本,这需要大约6秒钟。 35000个字符和一个ca. 5000条,这太慢了。似乎时间复杂度为O(t * n),因为对于每个t术语,文本必须扫描一次。这里有明显的性能错误吗?什么是可能的优化和/或更好的算法?

1 个答案:

答案 0 :(得分:1)

这可以在n O(t * log(n))中工作。我目前有两个在生产中运行的实现

实施#1:

完成纯Python。我从(较小的)模式文件构造了一个搜索树,其中树的每个节点都是一个字母,链接到可能的下一个字母的哈希。例如,你有三种模式:猫,狗和闪避。以下树在O(n)中自动构造:

{
    'c': {'a': {'t': 'cat'}},
    'd': {'d': {'g': {'e': 'dodge'}},
          'o': {'g': 'dog'}}
}

您现在可以扫描文本并在O(log(n))中查找此查找树中的每个单词(或每个字符)。

虽然有可能,但我不支持此解决方案的正则表达式。缺点是Python没有很好的性能,而哈希树在消耗多少内存方面效率低下。我打算使用Pypy,用Perl或C重写它并进行多处理。

实施#2:

一个名为grep的知名工具已经完成了上述所有工作。它支持正则表达式,可以接受模式文件。由于某种原因,它不喜欢大型模式文件,并且随着模式文件的增加,其性能呈指数级降低。这可能是因为我大量使用正则表达式。我最终在多个切片中分割模式文件,并在并行进程中将它们提供给grep。对于我的应用程序,grep的速度提高了10倍。注意:将环境变量$ LANG设置为'',因为grep受到严重的本地化缓慢的阻碍。

结论:

在C中构建目标引擎将是理想的选择,但通过使用可用且广泛使用的GPL工具可以为您节省几个月的生命。