Извлечение текста между двумя строками, если вложенная строка присутствует между этими двумя строками

#apache-spark #pyspark #apache-spark-sql

#apache-spark #pyspark #apache-spark-sql

Вопрос:

У меня есть необработанный текст в столбце с именем «сообщение», как показано ниже:

Пример фрейма данных

 Date               message
2020-11-01         ['some not required text1', 'Startstring , 
                   'some not required text2', MandatorySubstring , 'some not 
                    required text3', 'ID :AB_CD, 'Stopstring' 'some not 
                    required text4', 'Startstring ID :cd_ab', 'some not 
                    required text5', 'ID :ghed','some not required text6', ID :zyx', 'Stopstring 'some 
                    not required text7']
2020-11-02         ['some not required text8', Startstring 'ID :ABCD', 
                   'some not required text9', 'ID :ED_GH', 'some not 
                    required text10', ID :X_YZ, Stopstring 'some not 
                    required text11', 'Startstring 
                    'some not required text12',MandatorySubstring 
                    'some not required text13', ID :z_yx', 'some not required text14''Stopstring 
                    'some not required text15']
 

Я ищу, чтобы извлечь строку сразу после ID: между Startstring и Stopstring, если между Startstring и Stopstring существует MandatorySubstring, и отбрасываю идентификаторы, если MandatorySubstring не существует между Startstring и Stopstring . За одну дату может быть несколько таких экземпляров.

Ожидаемый результат:

 Date               message
2020-11-01         AB_CD 
2020-11-02         z_yx

 

Я попробовал следующий шаблон:

 pattern = StartStrings*((?:(?!StartString).)*?MandatoryString 1.*?)s*Stopstring
 

Это дает мне весь текст между startstring и stoptstring . Я понятия не имею, как извлечь текст сразу после ID: из этого текста сейчас.

Кто-нибудь может предоставить мне шаблон регулярных выражений для этого сценария? Помощь в этом отношении высоко ценится. Спасибо

Комментарии:

1. Я думаю, в вашем примере отсутствуют некоторые заключительные кавычки?

2. Это не должно иметь значения. Тип данных для столбца с именем «сообщение» — str, а все значение перед каждой датой — это всего одна строка (необработанный текст). Надеюсь, это прояснило ваш вопрос?

Ответ №1:

Учитывая текущий ввод, я бы предложил

 Startstring(?:(?!Startstring).)*?MandatorySubstring(?:(?!Startstring).)*?,['s]*IDs*:s*([^',]*).*?Stopstring
 

Смотрите демонстрацию регулярных выражений. Подробные сведения:

  • Startstring — разделитель слева
  • (?:(?!Startstring).)*? — любые нулевые или более символов, каждый из которых не запускает последовательность Startstring символов
  • MandatorySubstring — строка, которая должна присутствовать между левыми и правыми разделителями
  • (?:(?!Startstring).)*? — любые нулевые или более символов, каждый из которых не запускает последовательность Startstring символов
  • , — запятая
  • ['s]* — ноль или более ' или пробел
  • ID — строка
  • s*:s* — двоеточие, заключенное в ноль или более пробелов
  • ([^',]*) — Группа 1: любые нулевые или более символов, кроме ' и ,
  • .*? — любые нулевые или более символов, кроме символов разрыва строки, как можно меньше
  • Stopstring — разделитель справа.

Ответ №2:

Мы можем сделать это в три этапа. Сначала используйте регулярное выражение для поиска в этих строках начальной строки, обязательной подстроки и конечной строки. Мы используем утверждения с отрицательным прогнозом, чтобы гарантировать, что обязательная подстрока действительно находится между двумя соседними строками start и stop. Как только у нас есть эти совпадения, мы извлекаем идентификаторы, присутствующие в каждом из них, и, наконец, сводим их в один список.

 def extract_ids(s):
    matches = re.findall(r'Startstring((?:(?!Startstring).)*)MandatorySubstring((?:(?!Stopstring).)*)Stopstring', s)
    all_ids = [re.findall(r'IDs*:([^,]*)', group) for match in matches for group in match]
    ids_flat = [i for l in all_ids for i in l]
    return ids_flat

s1 = """['some not required text1', 'Startstring , 'some not required text2', MandatorySubstring , 'some not required text3', 'ID :AB_CD, 'Stopstring' 'some not required text4', 'Startstring ID :cd_ab', 'some not required text5', 'ID :ghed','some not required text6', ID :zyx', 'Stopstring 'some not required text7']"""

s2 = """['some not required text8', Startstring 'ID :ABCD', 'some not required text9', 'ID :ED_GH', 'some not required text10', ID :X_YZ, Stopstring 'some not required text11', 'Startstring 'some not required text12',MandatorySubstring 'some not required text13', ID :z_yx', 'some not required text14''Stopstring 'some not required text15']"""

>>> extract_ids(s1)
['AB_CD']

>>> extract_ids(s2)
["z_yx'"]
 

Чтобы применить это к вашему фрейму данных, просто используйте df['message'].map(extract_ids) .

Комментарии:

1. Отредактировал мой вопрос для ясности. пожалуйста, посмотрите. Спасибо