是否有Pythonic方法使这种逻辑更优雅?

时间:2010-09-24 01:59:58

标签: python

我是Python的新手,我一直在玩它来完成简单的任务。我有一堆CSV需要以复杂的方式操作,但我为了学习Python而将其分解为更小的任务。

现在,给定一个字符串列表,我想删除字符串中任何名称的用户定义的标题前缀。包含名称的任何字符串将仅包含 名称,带有或不带标题前缀。我有以下,它有效,但它感觉不必要的复杂。是否有更多的Pythonic方法来做到这一点?谢谢!

# Return new list without title prefixes for strings in a list of strings.
def strip_titles(line, title_prefixes):
    new_csv_line = []
    for item in line:
        for title_prefix in title_prefixes:
            if item.startswith(title_prefix):
                new_csv_line.append(item[len(title_prefix)+1:])
                break
            else:
                if title_prefix == title_prefixes[len(title_prefixes)-1]:
                    new_csv_line.append(item)
                else:
                    continue
    return new_csv_line

if __name__ == "__main__":
    test_csv_line = ['Mr. Richard Stallman', 'I like cake', 'Mrs. Margaret Thatcher', 'Jean-Claude Van Damme']
    test_prefixes = ['Mr.', 'Ms.', 'Mrs.']
    print strip_titles(test_csv_line, test_prefixes)

3 个答案:

答案 0 :(得分:9)

[re.sub(r'^(Mr|Ms|Mrs)\.\s+', '', s) for s in test_csv_line]

答案 1 :(得分:1)

假设prefixes是可变的,可能是本地化的一个方面,或者你不想因为其他原因而不使用正则表达式,你可以这样做(未经测试的代码):

def strip_title(string, prefixes):
    for prefix in prefixes:
         if string.startswith(prefix + ' '):
             return string[len(prefix) + 1:]
    return string

stripped = (list(strip_title(cell, prefixes) for cell in line)
            for line in lines)

这不是特别有效,因为算法最终会进行大量冗余检查(例如,如果行以M开头则检查三次)。这种事情是使用正则表达式的一个重要原因。

或者,您可以通过转义每个前缀并将它们与|分支连接来动态构建正则表达式:

def TitleStripper(prefixes):
    import re
    escaped_titles = (re.escape(prefix) for prefix in prefixes)
    prefix_re = re.compile('^({0}) '.format('|'.join(escaped_titles)))
    def strip_title(string):
        return prefix_re.sub('', string, 1)
    return strip_title

函数TitleStripper创建一个闭包函数strip_title,它与前一个函数一样,但是是为一组特定的前缀而构建的。致电strip_title = TitleStripper(prefixes)后,您只需致电strip_title(string)

主要是由于使用正则表达式,这比第一种方法快一点,可能是以清晰度为代价。

如果你真的只需要检查三个前缀,那么这些方法中的任何一个都是过度的,你应该使用另一个答案中解释的静态RE。

答案 2 :(得分:1)

更Pythonic方法是将{end of list'检查替换为else:循环的for item in line:子句。如果for循环完成而不被中断,else将被执行:

# Return new list without title prefixes for strings in a list of strings.    
def strip_titles(line, title_prefixes):
    new_csv_line = []
    for item in line:
        for title_prefix in title_prefixes:
            if item.startswith(title_prefix):
                new_csv_line.append(item[len(title_prefix)+1:])
                break
        else:
            new_csv_line.append(item)
    return new_csv_line

逻辑与你的逻辑相同。