Как найти шаблон регулярного выражения в нескольких строках текста с помощью re.DOTALL? - PullRequest
0 голосов
/ 29 декабря 2018

Я юрист и начинающий питон, поэтому я (а) тупой и (б) совершенно не в своей жизни.

Я пытаюсь применить шаблон регулярных выражений к текстовому файлу.Шаблон может иногда растягиваться на несколько строк.Меня особенно интересуют эти строки из текстового файла:

Considered  and  decided  by  Hemingway,  Presiding  Judge;  Bell, 
Judge;  and \n
 \n
Dickinson, Emily, Judge.

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

import re
def judges():
    presiding = re.compile(r'by\s*?([A-Z].*),\s*?Presiding\s*?Judge;', re.DOTALL)
    judge2 = re.compile(r'Presiding\s*?Judge;\s*?([A-Z].*),\s*?Judge;', re.DOTALL)
    judge3 = re.compile(r'([A-Z].*), Judge\.', re.DOTALL)
    with open("text.txt", "r") as case:
        for lines in case:
            presiding_match = re.search(presiding, lines)
            judge2_match = re.search(judge2, lines)
            judge3_match = re.search(judge3, lines)
            if presiding_match or judge2_match or judge3_match:
                print(presiding_match.group(1))
                print(judge2_match.group(1))
                print(judge3_match.group(1))
                break

Когда я его запускаю, я могу получить Хемингуэя и Белла, но затем я получаю «AttributeError: объект NoneType» не имеет атрибута «группа» длятретий судья после двух разрывов строк.

После проб и ошибок я обнаружил, что мой код читает только первую строку (до тех пор, пока «Bell, Judge; and») не завершится.Я думал, что re.DOTALL решит это, но я не могу заставить его работать.

Я пробовал миллион способов перехвата строк и получения всего этого, включая re.match, re.DOTALL, re.MULTILINE, "" .join, "" .join (lines.strip).()), и все, что я могу бросить к стене, чтобы сделать палку.

Через пару дней я поклонился просьбе о помощи.Спасибо за все, что вы можете сделать.

(Кроме того, мне не повезло заставить регулярное выражение работать с символами ^ и $. Кажется, он также ненавидит. Escape в регулярном выражении jud3).

Ответы [ 3 ]

0 голосов
/ 29 декабря 2018

Вместо нескольких re.search, вы можете использовать re.findall с очень коротким и простым шаблоном, чтобы найти всех судей одновременно:

import re

text = """Considered  and  decided  by  Hemingway,  Presiding  Judge;  Bell, 
Judge;  and \n
 \n
Dickinson, Emily, Judge."""

matches = re.findall(r"(\w+,)?\s(\w+),(\s+Presiding)?\s+Judge", text)
print(matches)

Какие отпечатки:

[('', 'Hemingway', '  Presiding'), ('', 'Bell', ''), ('Dickinson,', 'Emily', '')]

Имеется вся необработанная информация: имя, фамилия и «председательствующий атрибут» (если председательствующий судья или нет) каждого судьи.После этого вы можете подать эту необработанную информацию в структуру данных, которая удовлетворяет вашим потребностям, например:

judges = []
for match in matches:
    if match[0]:
        first_name = match[1]
        last_name = match[0]
    else:
        first_name = ""
        last_name = match[1]
    presiding = "Presiding" in match[2]
    judges.append((first_name, last_name, presiding))
print(judges)

, которая печатает:

[('', 'Hemingway', True), ('', 'Bell', False), ('Emily', 'Dickinson,', False)]

Как видите, теперь у вас естьсписок кортежей, где первый элемент - это имя (если оно указано в тексте), второй элемент - фамилия, а третий элемент - bool независимо от того, является ли судья председательствующим или нет.

Очевидно, что шаблон работает для вашего примера.Однако, поскольку (\w+,)?\s(\w+),(\s+Presiding)?\s+Judge является таким простым шаблоном, необходимо учитывать некоторые крайние случаи, когда шаблон может вернуть неправильный результат:

  • Будет сопоставлено только одно имя.Имя типа Dickinson, Emily Mary приведет к тому, что Mary будет определено как фамилия.
  • Фамилии, например de Broglie, приведут к совпадению только с Broglie, поэтому de будет потеряно.
  • ...

Вам нужно будет узнать, соответствует ли это вашим потребностям или предоставить дополнительную информацию по вашему вопросу о ваших данных.

0 голосов
/ 30 декабря 2018

Предполагая, что вы можете прочитать файл сразу (т.е. файл не слишком большой).Вы можете извлечь информацию о судье следующим образом:

import re

regex = re.compile(
    r'decided\s+by\s+(?P<presiding_judge>[A-Za-z]+)\s*,\s+Presiding\s+Judge;'
    r'\s+(?P<judge>[A-Za-z]+)\s*,\s+Judge;'
    r'\s+and\s+(?P<extra_judges>[A-Za-z,\s]+)\s*,\s+Judge\.?',
    re.DOTALL | re.MULTILINE
)

filename = 'text.txt'
with open(filename) as fd:
    data = fd.read()

for match in regex.finditer(data):
    print(match.groupdict())

с образцом входного текстового файла (text.txt), выглядящим следующим образом , с выходным значением:

{'judge': 'Bell', 'extra_judges': 'Dickinson, Emily', 'presiding_judge': 'Hemingway'}
{'judge': 'Abel', 'extra_judges': 'Lagrange, Gauss', 'presiding_judge': 'Einstein'}
{'judge': 'Dirichlet', 'extra_judges': 'Fourier, Cauchy', 'presiding_judge': 'Newton'}

Вы также можете поиграть с этим на regex101 site

0 голосов
/ 29 декабря 2018

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

Вы должны прочитать более одной строки.Если файл достаточно мал, просто прочитайте его как одну строку:

with open("text.txt", "r") as case:
    case_text = case.read()

, затем примените ваши регулярные выражения к этой одной строке.

Или вы можете протестировать каждый из соответствующих объектов в отдельности., а не как группа, и выведите только те, которые соответствуют:

if presiding_match:
    print(presiding_match.group(1))
elif judge2_match:
    print(judge2_match.group(1))
elif judge3_match:
    print(judge3_match.group(1))

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

Обратите внимание, что шаблоны, которые вы подходите, не разбиты на строки, поэтому флаг DOTALL здесь на самом деле не нужен.Вы сопоставляете .* текст, поэтому вы рискуете сопоставить слишком много , если вы используете DOTALL:

>>> import re
>>> case_text = """Considered  and  decided  by  Hemingway,  Presiding  Judge;  Bell, Judge;  and
...
... Dickinson, Emily, Judge.
... """
>>> presiding = re.compile(r'by\s*?([A-Z].*),\s*?Presiding\s*?Judge;', re.DOTALL)
>>> judge2 = re.compile(r'Presiding\s*?Judge;\s*?([A-Z].*),\s*?Judge;', re.DOTALL)
>>> judge3 = re.compile(r'([A-Z].*), Judge\.', re.DOTALL)
>>> presiding.search(case_text).groups()
('Hemingway',)
>>> judge2.search(case_text).groups()
('Bell',)
>>> judge3.search(case_text).groups()
('Considered  and  decided  by  Hemingway,  Presiding  Judge;  Bell, Judge;  and \n\nDickinson, Emily',)

Я бы хотя бы заменил [A-Z].* на[A-Z][^;\n]+, до не менее , исключая совпадающие ; точки с запятой и символы новой строки и сопоставляя только имена длиной не менее 2 символов.Просто сбросьте флаги DOTALL:

>>> presiding = re.compile(r'by\s*?([A-Z][^;]+),\s+?Presiding\s+?Judge;')
>>> judge2 = re.compile(r'Presiding\s+?Judge;\s+?([A-Z][^;]+),\s+?Judge;')
>>> judge3 = re.compile(r'([A-Z][^;]+), Judge\.')
>>> presiding.search(case_text).groups()
('Hemingway',)
>>> judge2.search(case_text).groups()
('Bell',)
>>> judge3.search(case_text).groups()
('Dickinson, Emily',)

Вы можете объединить три шаблона в один:

judges = re.compile(
    r'(?:Considered\s+?and\s+?decided\s+?by\s+?)?'
    r'([A-Z][^;]+),\s+?(?:Presiding\s+?)?Judge[.;]'
)

, который может найти всех судей в ваших входах за один раз с помощью .findall():

>>> judges.findall(case_text)
['Hemingway', 'Bell', 'Dickinson, Emily']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...