#python #regex #text #regex-group
#python #регулярное выражение #текст #регулярное выражение-группа
Вопрос:
Рассмотрим следующую строку
text2 = '''
Mr. Schafer
Mr Smith
Ms Davis
Mrs. Robinson
Mr. T
'''
Я хочу, чтобы регулярное выражение соответствовало полному имени, как в ‘Mr . Например, Schafer
Использование finditer():
matches = re.finditer(r'(Mr|Ms|Mrs).?s[A-Z]w*', text2)
for match in matches:
print(match)
Результаты:
<_sre.SRE_Match object; span=(1, 12), match='Mr. Schafer'>
<_sre.SRE_Match object; span=(13, 21), match='Mr Smith'>
<_sre.SRE_Match object; span=(22, 30), match='Ms Davis'>
<_sre.SRE_Match object; span=(31, 44), match='Mrs. Robinson'>
<_sre.SRE_Match object; span=(45, 50), match='Mr. T'>
finditer() дает мне результаты, которые я хочу, но не в списке.
Но когда я использую findall():
re.findall(r'(Mr|Ms|Mrs).?s[A-Z]w*', text2)
Результаты:
['Mr', 'Mr', 'Ms', 'Mrs', 'Mr']
Почему это так? Как я могу получить желаемый результат, используя findall() Я хочу
этот результат:
['Mr. Schafer', 'Mr Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']
Комментарии:
1. Вам нужно сделать группу без захвата:
re.findall(r'(?:Mr|Ms|Mrs).?s[A-Z]w*', text2)
, иначе она вернет захваченную группу вместо всего сопоставленного шаблона.2. Я предпочитаю
finditer
overfindall
, поскольку iter не будет считывать все данные в ОЗУ, поскольку он возвращает итерацию, в то время как find all возвращает список. Чтобы получить значения, просто используйте.group()
. Смотрите мой пример ниже.
Ответ №1:
Список, возвращаемый re.findall
содержит:
- текст каждого совпадения, если регулярное выражение не имеет захватов
- текст захвата в каждом совпадении, если регулярное выражение имеет ровно один захват
- кортеж подстрок, соответствующих каждому захвату, если регулярное выражение имеет более одного захвата.
Захват является частью регулярного выражения, заключенного в круглые скобки, если вы не используете (?:...)
; ?:
в этом контексте указывает библиотеке регулярных выражений Python не рассматривать круглые скобки как определяющие захват. (Конечно, он все еще используется для группировки.)
Итак, самое простое (и, вероятно, самое быстрое) решение — убедиться, что в регулярном выражении нет захватов, используя (?:...)
для окружения заголовка, а не просто (...)
:
>>> re.findall(r'(?:Mr|Ms|Mrs).?s[A-Z]w*', text2)
['Mr. Schafer', 'Mr Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']
Вы также можете явно записать полное имя:
>>> re.findall(r'((?:Mr|Ms|Mrs).?s[A-Z]w*)', text2)
['Mr. Schafer', 'Mr Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']
В этом случае нет особого смысла делать это, но форма «один захват» может быть полезна, если вы хотите, чтобы часть шаблона не отображалась в выходных данных.
Наконец, вам может понадобиться как почетное имя, так и фамилия в кортеже:
>>> re.findall(r'(?:(Mr|Ms|Mrs).?s([A-Z]w*))', text2)
[('Mr', 'Schafer'), ('Mr', 'Smith'), ('Ms', 'Davis'), ('Mrs', 'Robinson'), ('Mr', 'T')]
Ответ №2:
Часть «()» является индикатором захвата.
добавьте «?:», чтобы установить не-захват.
import re
text2 = '''
Mr. Schafer
Mr Smith
Ms Davis
Mrs. Robinson
Mr. T
'''
print(re.findall(r"(?:Mr|Ms|Mrs).?s[A-Za-z]*w*", text2))
# ['Mr. Schafer', 'Mr Smith', 'Ms Davis', 'Mrs. Robinson', 'Mr. T']
https://regexr.com/
имеет чит-лист с левой стороны.
Ответ №3:
Я предпочитаю finditer
over findall
. finditer
возвращает итератор совпадающих объектов в тексте, одновременно findall
возвращая список совпадающих шаблонов в тексте. Для эффективности генераторы лучше, чем список, поскольку список всех считывает данные в память, а уровень — нет. Чтобы получить значения из iterator
just use .group()
.
import re
text2 = '''
Mr. Schafer
Mr Smith
Ms Davis
Mrs. Robinson
Mr. T
'''
matches = re.finditer(r'(Mr|Ms|Mrs).?s[A-Z]w*', text2)
match_list = [match.group() for match in matches]
print(match_list)