Regex Python тянет между () - PullRequest
       0

Regex Python тянет между ()

2 голосов
/ 04 марта 2020

Я пытаюсь найти правильные имена и даты в скобках в Python с помощью регулярных выражений, но по какой-то причине мне кажется, что ничего не работает. Хотя я ожидаю, что это простой ответ, он меня вешает. Кто-нибудь может предложить решение?

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

Типичным предложением было бы следующее:

"Корреляционные факторы в молодежном насилии по-прежнему не совсем понятны и часто используются по умолчанию для переменных SES (Sheffield, 1998)."

Что я попытка извлечения данных (Шеффилд, 1998). Это всегда будет появляться в этом шаблоне. Мой ожидаемый результат будет

[(Sheffield, 1998)]

Мой текущий код:

import re

test_text = ['Sentence 1 (Author, 2019).', 
        'Sentence 2 (Another Author, 2020)',
        'Sentence 3 (First Author & Second Author, 2018)',
        'Sentence 4 (Author, 2019; Another Author, 2020; Fourth Author, 2017)']

test_list = []

for elem in test_text:
    test_run = re.findall(r'\((\D+), (\d+)\w*\)', str(elem))

    if test_run: #if something was found
       test_list.append(test_run) 

    print(elem) #print out to see what is going on

    print(str(test_run), '\n') #print out to see what is going on

print("FULL LIST OF PULL:\n", test_list)

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

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

Заранее спасибо.

Ответы [ 3 ]

2 голосов
/ 04 марта 2020

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

\(([^()]+), *(\d{4})\)\.? *$

Демо .

Регулярное выражение можно сделать самодокументирующим, написав его в в свободном интервале mode :

/
\(        # match '('
([^()]+)  # match 1+ chars other than '(' and ')' in capture group 1
,\ *      # match ',' followed by 0+ spaces
(\d{4})   # match four digits in capture group 2
\)        # match ')'      
\.?       # optionally match '.'
\ *       # match 0+ spaces
$         # match end-of-line
/x        # free-spacing regex definition mode

Обратите внимание, что в свободном интервале пробелы удаляются до анализа выражения. Поэтому места, предназначенные для присутствия, должны быть защищены от удаления. Я решил избежать их, но вместо этого их можно поместить в класс персонажа [ ] или заменить на [[:space:]], \p{Space} или, при необходимости, \s.

2 голосов
/ 05 марта 2020

Один из способов - использовать шаблон и извлечь то, что находится между круглыми скобками, используя группу захвата ([^()]+) и класс отрицательных символов, соответствующий любому символу, кроме ( или ). Это немного общий шаблон:

\(([^()]+)\)

Regex demo

Вы можете сделать его более конкретным c, указав, что вы разрешите использовать символ класс и повторяющиеся группы, чтобы немного приблизиться к формату данных:

\((\w+(?: [\w&]+)*, \d{4}(?:; \w+(?: [\w&]+)*, \d{4})*)\)
  • \( Соответствие (
  • ( Capture группа 1
    • \w+ Совпадение с 1+ символами слов,
    • (?: [\w&]+)*, \d{4} повторение 0+ раз с пробелом, 1+ слов с символами или &, пробел и 4 цифры
    • (?:; \w+(?: [\w&]+)*, \d{4})* Повтор предыдущего шаблона 0+ раз, перед которым стоит ;
  • ) Закрыть группу
  • \) Матч )

Regex demo

import re

test_text = ['Sentence 1 (Author, 2019).',
             'Sentence 2 (Another Author, 2020)',
             'Sentence 3 (First Author & Second Author, 2018)',
             'Sentence 4 (Author, 2019; Another Author, 2020; Fourth Author, 2017)']

test_list = []
pattern = r'\(([^()]+)\)'

for elem in test_text:
    for splitOne in re.search(pattern, elem).group(1).split(";"):
        for splitTwo in splitOne.split(":"):
            test_list.append(splitTwo.strip())

print("FULL LIST OF PULL:\n", test_list)

Output

FULL LIST OF PULL:
 ['Author, 2019', 'Another Author, 2020', 'First Author & Second Author, 2018', 'Author, 2019', 'Another Author, 2020', 'Fourth Author, 2017']

Или создайте список списков, используя, например, this Python demo .


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

Например:

(?<=\([^()]*)\w+(?: [\w&]+)*, \d+(?=[^\r\n()]*\))

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

Regex demo (Javascript выбрано только для демонстрационных целей) | Или посмотрите Python демо

0 голосов
/ 04 марта 2020

Сбой, потому что ваше регулярное выражение содержит круглые скобки, поэтому оно действительно работает только для одной пары (имя, год) на выражение в скобках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...