代码之家  ›  专栏  ›  技术社区  ›  Ma0

带列表的高效正则表达式

  •  1
  • Ma0  · 技术社区  · 6 年前

    我有一个字符串列表 os.listdir() 如下所示:

    ['foo',
     'bar'
     'backup_20180406'
     ...]
    

    从这些条目中,我想得到那些符合 “备份” 模式。使用命名组的regex将是

    regex = r"BACKUP_(?P<date>\d+)"
    

    我试图创建一个包含 仅限日期 从上面(又名 .group('date') ,但如果不解析两次字符串,我就找不到方法。

    res = [re.search(regex, x).group('date') for x in filter(r.match, os.listdir(folder))]
    

    我确信我遗漏了一些非常明显和简洁的东西,那么有没有更好的方法呢?

    3 回复  |  直到 6 年前
        1
  •  3
  •   Holger Bille    6 年前

    我通常会:

    regex = re.compile(r"BACKUP_(?P<date>\d+)")
    a = ['foo', "BACKUP_20180406", 'xxx']
    matches = [regex.match(x) for x in a]
    valid = [x.group('date') for x in matches if x]
    

    或者只是

    valid = [x.group('date') for x in (regex.match(y) for y in a) if x]
    
        2
  •  3
  •   andrew_reece    6 年前

    这是熊猫解决方案,使用 extract() :

    import pandas as pd
    
    strings = ['foo', 'bar', 'backup_20180406']
    regex = r"backup_(?P<date>\d+)"
    
    pd.Series(strings).str.extract(regex).dropna()
    
    2    20180406
    Name: date, dtype: object
    
        3
  •  -1
  •   Gelineau    6 年前

    如果要测试一个简单的模式,regex很少是最有效的工具。 只需使用startswith,速度就会提高一倍。

    from timeit import timeit
    import re
    
    size = 10000
    data = ['foo','bar','backup_20180406'] * size
    
    def find_dates(data):
        prefix = 'backup_'
        prefix_size = len(prefix)
        return [name[prefix_size:] for name in data if name.startswith(prefix)]
    
    def find_dates_testing_numbers(data):
        prefix = 'backup_'
        prefix_size = len(prefix)
        for name in data:
            if name.startswith(prefix):
                try:
                    yield int(name[prefix_size:])
                except ValueError:
                    pass
    
    def find_dates_regex(data):
        regex = re.compile(r"backup_(?P<date>\d+)")
        return [x.group('date') for x in (regex.match(y) for y in data) if x]
    
    def find_dates_pd(data):
        import pandas as pd
        regex = r"backup_(?P<date>\d+)"
        return pd.Series(data).str.extract(regex).dropna()
    
    result = find_dates(data)
    print(timeit('find_dates(data)', globals=globals(), number=1000))
    # 4.02514289499959 seconds
    
    print(timeit('list(find_dates_testing_numbers(data))', globals=globals(), number=1000))
    # 6.0529899510002 seconds
    
    print(timeit('find_dates_regex(data)', globals=globals(), number=1000))
    # 8.772153561999403 seconds
    
    print(timeit('find_dates_pd(data)', globals=globals(), number=1000))
    # 19.018224569999802