如何提高这种递归函数的性能?

时间:2011-06-30 17:24:14

标签: python performance recursion

我正在尝试编写一个函数来搜索str的substr,考虑到编写奇怪字母的不同可能性,例如丹麦语中的æ,ø,å。例如,你可以搜索'Ålborg',如果有的话,函数将返回true,在str中说'Aalborg'。

以下功能有效,但性能难以忍受。你会建议什么来改善表现?

def danish_tolerating_search(substr, str):
    '''Figure out if substr is in str, taking into account
    possible deviations in writing letters æ, ø, å.
    æ  <->  ae a ea
    ø  <->  oe o
    å  <->  aa a o
    '''

    # normalize input
    substr = substr.lower().replace('aa',u'å')
    str = str.lower()

    # normalized recursive search
    # TODO fix perfomance
    def s(substr, str):
        if str.find(substr) >= 0: return True
        if substr.find(u'æ') >= 0:
            if    s(substr.replace(u'æ','ae', 1), str): return True
            elif  s(substr.replace(u'æ', 'a', 1), str): return True
            elif  s(substr.replace(u'æ','ea', 1), str): return True
        if str.find(u'æ') >= 0:
            if    s(substr, str.replace(u'æ','ae', 1)): return True
            elif  s(substr, str.replace(u'æ', 'a', 1)): return True
            elif  s(substr, str.replace(u'æ','ea', 1)): return True
        if substr.find(u'ø') >= 0:
            if    s(substr.replace(u'ø','oe', 1), str): return True
            elif  s(substr.replace(u'ø', 'o', 1), str): return True
        if str.find(u'ø') >= 0:
            if    s(substr, str.replace(u'ø','oe', 1)): return True
            elif  s(substr, str.replace(u'ø', 'o', 1)): return True
        if substr.find(u'å') >= 0:
            if    s(substr.replace(u'å','aa', 1), str): return True
            elif  s(substr.replace(u'å', 'a', 1), str): return True
            elif  s(substr.replace(u'å', 'o', 1), str): return True
        if str.find(u'å') >= 0:
            if    s(substr, str.replace(u'å','aa', 1)): return True
            elif  s(substr, str.replace(u'å', 'a', 1)): return True
            elif  s(substr, str.replace(u'å', 'o', 1)): return True
        return False

    return s(substr, str)

3 个答案:

答案 0 :(得分:3)

我认为你应该完全消除递归。例如,您可以决定输入字符串的“正常形式”,相应地转换它们(即替换那些“含糊不清的”字符)而不是完成findreplace的所有操作。简单

return substring in string_

另请注意,您不需要同时调用findreplace,后者就足够了。如果找不到搜索字符串,则替换只是不会替换任何内容。

答案 1 :(得分:3)

尝试

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

def danish_tolerating_search(search, content):
    search = search.lower()
    content = content.lower()

    variants = {
        u'a': u'[aæå]',
        u'o': u'[oøå]',
        u'ae': u'(?:ae|æ)',
        u'ea': u'(?:ea|æ)',
        u'aa': u'(?:aa|å)',
        u'oe': u'(?:oe|ø)',
        u'\\å': u'(?:[oå]|aa?)',
        u'\\ø': u'(?:ø|oe?)',
        u'\\æ': u'(?:æ|ae?|ea)',
    }

    search = re.escape(search)
    search = re.sub(ur'[ae]a|[ao]e?|\\[åøæ]', lambda m: variants[m.group(0)], search)
    return re.search(search, content) is not None

我没有测试它的性能,因为OP没有发布任何内容。我只是假设正则表达式引擎比以递归方式调用OP的s()并执行大量.find.replace更优化。

这里,搜索字符串中的关键字母被正则表达式中可能的等价类替换,例如, Ålborg变为(?:[oå]|aa?)lb[oøå]rg。这个正则表达式应该包括@ 101100提到的所有可能的变体,相当于Ålborg(ålbørg“或”ålbårg“或”aalborg“或”aalbørg“或”aalbårg“或”alborg“或”albørg“或”albårg“)评论)。然后根据上下文搜索正则表达式。

答案 2 :(得分:1)

这是解析器的经典示例。阅读lex和yacc之类的内容,你不需要他们所有的功能,但原则仍然适用。

之后,使用python re模块匹配相应的正则表达式。如果您需要更多功能,请使用pyparsing库。

def danish_tolerating_search(substr, str):
'''Figure out if substr is in str, taking into account
possible deviations in writing letters æ, ø, å.
æ  <->  ae a ea
ø  <->  oe o
å  <->  aa a o
for all of these combinations replace with appropriate regex as in example
'''
substring = substring.lower().replace('aa', '[ae]{1,2}')
string = string.lower()
re.search(substring, string)