Эффективное регулярное выражение со списками - PullRequest
0 голосов
/ 04 июня 2018

У меня есть список строк из os.listdir(), который выглядит следующим образом:

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

из этих записей, я хочу получить те, которые соответствуют "backup_YYYYMMDD" шаблон.Регулярное выражение для этого с именованными группами было бы

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 ]

0 голосов
/ 04 июня 2018

Я обычно делаю:

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]
0 голосов
/ 04 июня 2018

Regex редко являются наиболее эффективными инструментами, если вы тестируете простой шаблон.Просто использование startwith делает его в два раза быстрее.

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
0 голосов
/ 04 июня 2018

Вот решение Pandas, использующее 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...