Получить список подстрок из списка строк, где подстроки соответствуют определенному регулярному выражению - PullRequest
0 голосов
/ 10 октября 2018

Этот вопрос для Python 3.6+ (но не стесняйтесь отвечать за более низкие Python для других читателей).

Я хочу извлечь подстроку из каждой строки, которая соответствует регулярному выражению.

Скажем, у меня есть следующее:

a = ['v-01-001', 'v-01-002', 'v-02-001', 'v-02-002', 'v-02-003', 'v-03-001']

Я хочу, чтобы последние 3 цифры всех строк соответствовали v-02-\d\d\d, то есть:

['001', '002', '003']

Моя наивная попытка:

[x[1] for x in list(map(lambda i: re.search(r'v-02-(\d\d\d)', i), a)) if x]

Можете ли вы придумать что-нибудь более элегантное?

Спасибо

Ответы [ 2 ]

0 голосов
/ 10 октября 2018

Четыре способа сделать это.

Первый - это просто обычный цикл ole:

li=[]
for s in a:
    m = re.search(r'v-02-(\d\d\d)', s)
    if m:
        li.append(m.group(1))
 # li=['001', '002', '003']

Второй в двух вызовах одного и того же регулярного выражения в понимании списка:

>>> [re.search(r'v-02-(\d\d\d)', s).group(1) for s in a if re.search(r'v-02-(\d\d\d)', s)]
['001', '002', '003']

Третье - использовать map:

>>> [m.group(1) for m in map(lambda s: re.search(r'v-02-(\d\d\d)', s), a) if m]
['001', '002', '003']

Наконец, вы можете сгладить список с помощью .join и затем использовать findall:

>>> re.findall(r'\bv-02-(\d\d\d)\b', '\t'.join(a))
['001', '002', '003']

Или используйте \n и re.M против двух \b:

>>> re.findall(r'^v-02-(\d\d\d)$', '\n'.join(a), flags=re.M)
['001', '002', '003']

Я бы написал это в том же порядке, если бы писал этот фрагмент кода.

То, что считается более изящным , в глазах смотрящего, я полагаю.Я бы посчитал, что последний будет более элегантным.


Вы также можете пропустить регулярное выражение и использовать строковые методы Python:

>>> prefix='v-02-'
>>> [e[len(prefix):] for e in filter(lambda s: s.startswith(prefix),a)]
['001', '002', '003']

Это, вероятно,будьте самыми быстрыми , если это имеет значение в этом случае.


В декабре 2019 года будет более элегантная альтернатива.Как определено в PEP 572 , вы сможете использовать оператор присваивания, чтобы вы могли назначить совпадение и проверить совпадение за один шаг:

[m.group(1) for s in a if (m:=re.search(r'v-02-(\d\d\d)', s))]
0 голосов
/ 10 октября 2018

Вы можете сделать что-то вроде этого:

import re

a = ['v-01-001', 'v-01-002', 'v-02-001', 'v-02-002', 'v-02-003', 'v-03-001']
pattern = re.compile('v-02-(\d{3})$')
print([m.group(1) for m in map(pattern.match, a) if m])

Вывод

['001', '002', '003']

Также вы можете использовать finditer:

print([m.group(1) for ms in map(pattern.finditer, a) for m in ms])

Выход

['001', '002', '003']
...