Этот вопрос относится к Python 3. 6+ (но не стесняйтесь отвечать за более низкие Pythons для других читателей).
Я хочу извлечь подстроку из каждой строки, которая соответствует регулярному выражению.
Скажем, у меня есть следующее:
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]
Можете ли вы придумать что-нибудь более элегантное?
Спасибо
Вы могли бы сделать что-то вроде этого:
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']
[m[1] for m in map(pattern.match, a) if m]
Четыре способа сделать это.
Первый - это просто обычная петля 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))]
d = [elem.split('v-02-')[1] for elem in a if elem.startswith('v-02')]