Используйте регулярное выражение для сопоставления нескольких слов в последовательности - PullRequest
0 голосов
/ 05 января 2020

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

  1. Если в строке «повторяющийся платеж разрешен», получите первый текст после «вкл» '
  2. Если в строке' повторяющийся платеж ', получите все до

В настоящее время я написал следующее:

#will be used in an apply statement for a column in dataframe
def parser(x):
    x_list = x.split()
    if " recurring payment authorized on " in x and x_list[-1]!= "on":
         return x_list[x_list.index("on")+1]
     elif " recurring payment" in x:
         return ' '.join(x_list[:x_list.index("recurring")])
     else:
         return None

Однако этот код выглядит неудобно и не крепкий Я хочу использовать регулярные выражения для сопоставления этих строк.

Вот несколько примеров того, что эта функция должна возвращать:

  1. recurring payment authorized on usps abc должна возвращать usps

  2. usps recurring payment abc должен вернуть usps

Любая помощь в написании регулярных выражений для этой функции будет принята с благодарностью. Входная строка будет содержать только текст; здесь не будет числовых и специальных символов

Ответы [ 4 ]

2 голосов
/ 05 января 2020

Использование Regex с lookahead и lookbehind сопоставление с образцом

import re

def parser(x):
    # Patterns to search
    pattern_on = re.compile(r'(?<= authorized on )(.*?)(\s+)')
    pattern_recur = re.compile(r'^(.*?)\s(?=recurring payment)')

    m = pattern_on.search(t)
    if m:
        return m.group(0)

    m = pattern_recur.search(t)
    if m:
        return m.group(0)

    return None

tests =  ["recurring payment authorized on usps abc", "usps recurring payment abc", "recurring payment authorized on att xxx xxx", "recurring payment authorized on 25.05.1980 xxx xxx", "att recurring payment xxxxx", "12.14.14. att recurring payment xxxxx"]


for t in tests:
    found = parser(t)
    if found:
        print("In text: {}\n Found: {}".format(t, found))

Выход

In text: recurring payment authorized on usps abc
 Found: usps 
In text: usps recurring payment abc
 Found: usps 
In text: recurring payment authorized on att xxx xxx
 Found: att 
In text: recurring payment authorized on 25.05.1980 xxx xxx
 Found: 25.05.1980 
In text: att recurring payment xxxxx
 Found: att 
In text: 12.14.14. att recurring payment xxxxx
 Found: 12.14.14. att 

Пояснение

Совпадение шаблонов Lookahead и Lookbehind

Regex Lookbehind

(? <= Foo) Lookbehind Утверждает, что немедленно текущей позиции в строке предшествует foo </p>

Итак, в шаблоне: r '(? <= авторизация включена) (. *?) (\ s +)' </p>

foo is " authorized on "
(.*?) - matches any character (? causes it not to be greedy)
(\s+) - matches at least one whitespace

Таким образом, вышеприведенное заставляет (. *?) Перехватывать все символы после «авторизации на» до первого символа пробела.

Regex Lookahead

(? = foo) Lookahead утверждает, что сразу за текущей позицией в строке следует foo

То есть: r '^ (. *?) \ s (? = повторяющийся платеж)'

foo is 'recurring payment'
^ - means at beginning of the string
(.*?) - matches any character (non-greedy)
\s - matches white space

Таким образом, (. *?) Будет соответствовать всем символам от начала строки до тех пор, пока мы не получим пробел, за которым следует «повторяющийся платеж»

Лучшая производительность Желательно sinc e Вы применяете к Dataframe, у которого может быть много столбцов.

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

def parser(x):
    # Use predined patterns (pattern_on, pattern_recur) from globals
    m = pattern_on.search(t)
    if m:
        return m.group(0)

    m = pattern_recur.search(t)
    if m:
        return m.group(0)

    return None

 # Define patterns to search
pattern_on = re.compile(r'(?<= authorized on )(.*?)(\s+)')
pattern_recur = re.compile(r'^(.*?)\s(?=recurring payment)')

tests =  ["recurring payment authorized on usps abc", "usps recurring payment abc", "recurring payment authorized on att xxx xxx", "recurring payment authorized on 25.05.1980 xxx xxx", "att recurring payment xxxxx", "12.14.14. att recurring payment xxxxx"]
0 голосов
/ 06 января 2020

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

Пожалуйста, дайте мне знать, если это работает, и как это работает против решения @ DarryIG.

0 голосов
/ 05 января 2020

Не уверен, что это быстрее, но Python имеет условия:

  • Если присутствует authorized on, тогда
    • соответствует следующей подстроке непробельных символов, иначе
    • соответствует всему, что происходит до recurring

Обратите внимание, что результат будет в группе захвата 2 или 3, в зависимости от того, какое совпадение.

import re

def xstr(s):
    if s is None:
        return ''
    return str(s)

def parser(x):
    # Patterns to search
    pattern = re.compile(r"(authorized\son\s)?(?(1)(\S+)|(^.*) recurring)")

    m = pattern.search(t)
    if m:
        return xstr(m.group(2)) + xstr(m.group(3))

    return None

tests =  ["recurring payment authorized on usps abc", "usps recurring payment abc", "recurring payment authorized on att xxx xxx", "recurring payment authorized on 25.05.1980 xxx xxx", "att recurring payment xxxxx", "12.14.14. att recurring payment xxxxx"]


for t in tests:
    found = parser(t)
    if found:
        print("In text: {}\n Found: {}".format(t, found))
0 голосов
/ 05 января 2020

Я не уверен, что для этого уровня сложности требуется RegEx.

Надеясь, что RegEx не является строгим требованием для вас, вот решение, не использующее его:

examples = [
'stuff more stuff recurring payment authorized on ExampleA useless data',
'other useless data ExampleB recurring payment',
'Not matching phrase payment example authorized'
]


def extract_data(phrase):
    result = None
    if "recurring payment authorized on" in phrase:
        result = phrase.split("recurring payment authorized on")[1].split()[0]
    elif "recurring payment" in phrase:
        result = phrase.split("recurring payment")[0]
    return result


for example in examples:
    print(extract_data(example))

Выход

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