Как использовать пользовательские регулярные выражения для более чем одного вызова? - PullRequest
0 голосов
/ 15 февраля 2020

edit: эта часть была решена, но у меня есть одна последняя проблема с моим кодом, см. Последний ответ.

У меня есть текстовый файл, структурированный следующим образом:

Name1 (Middlename1) LastName
Birthyear
Name2 (Middlename2) LastName
Birthyear
...
NameN (MiddlenameM) LastName
Birthyear

I'm пытаясь использовать RE для автоматического поиска имени и года, но я не знаю, как объединить два RE, поскольку обе информации не находятся в одной строке:

import re
regexp = re.compile(  r'(( )*)(?P<name>([a-zA-Z]*)( [a-zA-Z]+)? ROCHE)\n'
                      r'(( )*)(?P<year>18\d\d)\n'
                   )

Два RE работают независимо, но не вместе. Как мне это сделать?

Ответы [ 2 ]

1 голос
/ 16 февраля 2020

Вы хотите одно регулярное выражение, которое сканирует строку, которая охватывает две строки. Затем вы хотите найти последовательные совпадения. Но сначала:

Имена, по крайней мере в sh говорящих на английском языке странах, могут содержать дефисы (Anne-Mar ie), апострофы (O'Donnell), точки (John Q. Publi c) ) и др. c. Поэтому я использую регулярное выражение, которое позволяет эти символы. Кроме того, люди могут иметь более одного второго имени. Я пытаюсь проиллюстрировать, как перебирать пары имя / год; вы можете настроить фактическое регулярное выражение в соответствии со своими требованиями.

Регулярное выражение:

^(?P<name>(?:[a-z.'-]+(?:\s+[a-z.'-]+)*))\n(?P<year>\d{4})$  Flags: re.M|re.I
  1. ^ Соответствует началу строки.
  2. [a-z.'-]+ Соответствует одному или нескольким буквам, точкам, 'или символам. Это элемент имени .
  3. (?:\s+[a-z.'-]+)* Соответствует одному или нескольким пробельным символам, за которыми следует элемент имени . Это повторяется 0 или более раз. Таким образом, именованная группа name состоит из 1 или более элементов name , разделенных одним или несколькими пробелами.
  4. \n Соответствует новой строке.
  5. (?P<year>\d{4})$ Соответствует 4 цифрам, за которыми следует конец строки или конец строки.

Флаг MULTILINE обрабатывает специальные привязки ^ и $, так что они совпадают в дополнение к начало и конец строки, начало и конец строки.

Код полагается на re.finditer для поиска последовательных совпадений:

import re

text = """John Doe
1921
John Q. Public
1987
Anne-Marie Smith
1989
Paul O'Donnell
2001
J. P. Marquand
1893
"""

regexp = re.compile(r"^(?P<name>(?:[a-z.'-]+(?:\s+[a-z.'-]+)*))\n(?P<year>\d{4})$", flags=re.M|re.I)
for m in regexp.finditer(text):
    name = m['name']
    year = m['year']
    # do something with name and year in the second file. Here we are just printing the values.
    print(name, year)

Печать:

John Doe 1921
John Q. Public 1987
Anne-Marie Smith 1989
Paul O'Donnell 2001
J. P. Marquand 1893
0 голосов
/ 16 февраля 2020

Вы должны использовать re.MULTILINE

r = re.compile(r'(( )*)(?P<name>([a-zA-Z]*)( [a-zA-Z]+)?)(( )+)(?P<surname>([a-zA-Z]+))\n(?P<year>18\d\d)', re.MULTILINE)

m = r.match("""Jan Sebastian  Bach
1892""")

Обновление # 1 Более полный пример с чтением двух строк из файла, а затем еще двух строк.

import re

r = re.compile(r'(( )*)(?P<name>([a-zA-Z]*)( [a-zA-Z]+)?)(( )+)(?P<surname>([a-zA-Z]+))\n(?P<year>18\d\d)', re.MULTILINE)

with open('people.txt') as f:
    while True:
        line1 = f.readline()
        line2 = f.readline()
        if not line2: break
        m = r.match(line1+line2)
        print("name:%s, surname:%s, year:%s" % (m.group('name'), m.group('surname'), m.group('year')))
...