Как сделать извлечение информации из фрагментированного текста в python? - PullRequest
4 голосов
/ 27 мая 2020

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

Over-ride Flag for Site/Laterality/Morphology (Interfield Edit 42)

This field is used to identify whether a case was reviewed and coding confirmed 
for paired-organ primary
site cases with an in situ behavior and the laterality is not coded right, 
left, or one side involved, right or left
origin not specified.

Code           Description

Blank          Not reviewed, or reviewed and corrected

1                  Reviewed and confirmed as reported: A patient had behavior 
code of in situ and laterality is not
stated as right: origin of primary; left: origin of primary; or only one side 
involved, right or left
origin not specified

This field is used to identify whether a case was reviewed and coding confirmed 
for cases with a non-
specific laterality code.

Code           Description

Blank1          Not reviewed

11                   A patient had laterality 
coded non-specifically and
extension coded specifically

This field, new for 2018, indicates whether a case was reviewed and coding    
............

Из приведенного выше свободного текста мне нужно хранить только значения кода и описания в двух списках, как показано ниже.

code = ["Blank", "1", "Blank1", "11"]
des = ["Not reviewed, or reviewed and corrected", "Reviewed and confirmed as reported: A patient had behavior code of in situ and laterality is not stated as right: origin of primary; left: origin of primary; or only one side involved, right or left origin not specified", "Not reviewed", "A patient had laterality coded non-specifically and extension coded specifically"]

Как это сделать в Python?

Примечание. Code может содержать «Пустой (или Blank1) "или числовое значение c. Иногда код Description разбивается на несколько строк. В приведенном выше примере я показываю, что один блок Code и Description содержит два кода и два описания. Однако один блок Code и Description может содержать один или несколько кодов и описаний.

Ответы [ 2 ]

3 голосов
/ 29 мая 2020

Мы можем решить эту проблему с помощью алгоритма / конечного автомата. Следующий код открывает ваш файл с именем «datafile.txt» в том же каталоге, что и сценарий python, анализирует его и распечатывает результаты. Ключи к алгоритму предполагают, что есть пустые строки только между каждыми двумя полями и что любая строка, содержащая начало поля описания, которое мы хотим записать, имеет атрибут кода, отделенный от атрибута описания тремя или больше мест. Эти предположения всегда будут верны, насколько я могу судить по фрагменту вашего файла.

index = -1
record = False
description_block = False
codes = []
descriptions = []
with open("datafile.txt", "r") as file:
  for line in file:
    line = [portion.strip() for portion in line.split("   ") if portion != ""]
    if record:
      if len(line) == 2:
        index += 1
        codes.append(line[0])
        descriptions.append(line[1])
      else:
        if line[0]:
          description_block = True
        if description_block:
          if not line[0]:
            description_block = False
            record = False
            continue
          else:
            descriptions[index] += " "+line[0]
    if line[0] == "Code":
      record = True
print("codes:", codes)
print("descriptions:", descriptions)

Результат:

codes: ['Blank', '1', 'Blank1', '11']
descriptions: ['Not reviewed, or reviewed and corrected', 'Reviewed and confirmed as reported: A patient had behavior code of in situ and laterality is not stated as right: origin of primary; left: origin of primary; or only one side involved, right or left origin not specified', 'Not reviewed', 'A patient had laterality coded non-specifically and extension coded specifically']

Проверено в python 3.8.2

EDIT: обновление кода для отражения всего файла данных, как указано в комментариях.

import re
column_separator = "     "
index = -1
record = False
block_exit = False
break_on_newline = False
codes = []
descriptions = []
templine = ""
def add(line):
  global index
  index += 1
  block_exit = False
  codes.append(line[0])
  descriptions.append(line[1])
with open("test", "r", encoding="utf-8") as file:
  while True:
    line = file.readline()
    if not line:
      break
    if record:
      line = [portion.strip() for portion in line.split(column_separator) if portion != ""]
      if len(line) > 1:
        add(line)
      else:
        if block_exit:
            record = False
            block_exit = False
        else:
          if line[0]:
            descriptions[index] += " "+line[0]
          else:
            while True:
              line = [portion.strip() for portion in file.readline().split(column_separator) if portion != ""]
              if not line:
                break
              if len(line) > 1:
                if templine:
                  descriptions[index] += templine
                  templine = ""
                add(line)
                break
              else:
                print(line)
                if line[0] and "Instructions" not in line[0]:
                  templine += " "+line[0]
                else:
                  if break_on_newline:
                    break_on_newline = False
                    record = False
                    templine = ""
                    break
                  else:
                    templine += " "+line[0]
                    break_on_newline = True
    else:
      if line == "Code           Description\n":
        record = True

print("codes:", codes)
print("\n")
print("descriptions:", descriptions)

# for i in range(len(codes)):
#   print(codes[i]+"\t\t", descriptions[i])
0 голосов
/ 27 мая 2020

Попробуйте следующий подход с использованием регулярных выражений:

blanks = re.findall(r'\bCode\b.*?\bDescription\s*?(\S+)\s+.*?\r?\n(\d+)\s+.*?(?=\r?\n\r?\n)', inp, flags=re.DOTALL)
print(blanks)

reviews = re.findall(r'\bCode\b.*?\bDescription\s*?\S+\s+(.*?)\r?\n\d+\s+(.*?)(?=\r?\n\r?\n)', inp, flags=re.DOTALL)

Это напечатает:

[('Blank', '1'), ('Blank1', '11')]

[('Not reviewed, or reviewed and corrected\n', 'Reviewed and confirmed as reported: A patient had behavior \ncode of in situ and laterality is not\nstated as right: origin of primary; left: origin of primary; or only one side \ninvolved, right or left\norigin not specified'), ('Not reviewed\n', 'A patient had laterality \ncoded non-specifically and\nextension coded specifically')]

Идея здесь состоит в том, чтобы просто сопоставить и захватить различные желаемые части Code ... Description ... Blank частей ваш вводимый текст. Обратите внимание: в этом ответе предполагается, что вы уже прочитали текст в строковую переменную Python.

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