Как извлечь имена сущностей, когда они разбиты на несколько строк большого текстового файла с python - PullRequest
0 голосов
/ 20 марта 2020

У меня большой текстовый файл в python, как показано ниже:

junk
junk
...
Company          Rent
--------        --------
Andy Candy       2000

Store            0.00

2135  

Moody Group      5000

4512             50%

....
....
junk
junk
....
repeat

Я хочу l oop через строки и извлечь номер счета и название компании. Когда это l oop через первые три строки, моя идея вывода должна быть такой, как показано ниже:

['2135','Andy Candy Store']

, а затем, когда l oop через следующие две строки, вывод будет:

['4512','Moody Group']

Я попытался с помощью приведенного ниже кода:

with open(filepath) as f:
    count=0
    for line in f:
        if line.find("----") == -1 and line != '\n' and re.search(
                "Company|Rent", line) == None:
            if re.match('^[a-zA-Z]', line) is not None:
                name = re.findall(r'\b([a-zA-Z]+)\b', line)
                name = ' '.join(name)
                print('name', name)
            elif re.match('^[0-9]', line) is not None:
                number = line.split(' ', 1)[0]
                out = str(number) + ', ' + str(name)
                out = out.split(', ')
                print(out)

Я получил результаты, как показано ниже:

['2135\n','Store']

Есть предложения, чтобы это исправить? Спасибо!

Ответы [ 2 ]

1 голос
/ 20 марта 2020

Ваш код немного адаптирован:

with open(filepath) as f:
    name = ''
    for line in f:
        if line and line.find("----") == -1 and re.search(
                "Company|Rent", line) is None:
            if re.match('^[a-zA-Z]', line) is not None:
                names = re.findall(r'\b([a-zA-Z]+)\b', line)
                names = ' '.join(names)
                name += names
            elif re.match('^[0-9]', line) is not None:
                number = line.split(' ', 1)[0]
                print([number, name])
                name = ''

Это предполагает, что вы уже правильно отделили мусор, и логика c сама по себе верна. Основным исправлением является объединение частей имени в последующих строках.

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

['2135', 'Andy Candy Store']
['4512', 'Moody Group']
0 голосов
/ 21 марта 2020

Вы можете использовать следующее регулярное выражение с флагами /gmi.

^Company\s+Rent\r?\n------*\s+-*\r?\n([a-z]+(?: [a-z]+)*).*\r?\n(?:([a-z]+(?: [a-z]+)*).*\r?\n)?(\d+)\s*\r?\n([a-z]+(?: [a-z]+)*).*\r?\n(?:([a-z]+(?: [a-z]+)*).*\r?\n)?(\d+)

Python демо

Это регулярное выражение имеет шесть групп захвата:

  1. Название компании, строка 1
  2. Название компании, строка 2 (необязательно)
  3. Numeri c идентификатор, следующий за названием компании
  4. Название группы, строка 1
  5. Имя группы, строка 2 (необязательно)
  6. Нумер c идентификатор, следующий за именем группы

Если название компании (группы) находится только в одной строке, группа захвата 2 (5) будет nil. Если название компании всегда в двух строках, а имя группы всегда в одной строке, как в примере, регулярное выражение может быть соответственно упрощено. Если название компании или группы может занимать более двух строк, регулярное выражение должно быть изменено соответствующим образом.

Это регулярное выражение выполняет следующие операции.

^
Company\s+Rent\r?\n # match line
------*\s+-*\r?\n   # match line

(               # begin cap grp 1 (company name 1)
  [a-z]+        # match 1+ ltrs 
  (?: [a-z]+)   # match 1 space, 1+ ltrs in non-cap grp
  *             # execute non-cap grp 0+ times
)               # end cap grp 1 
.*\r?\n         # match remainder of line

(?:             # begin non-cap grp
  (             # begin cap grp  2  (opt. company name 2)             
    [a-z]+      # match 1+ ltrs
    (?: [a-z]+) # match 1 space, 1+ ltrs in non-cap grp
    *           # execute non-cap grp 0+ times
  )             # end cap grp 2
  .*\r?\n       # match remainder of line
)               # end non-cap group 
?               # optionally match non-cap grp

(\d+)           # match 1+ digits in cap grp 3 (company id)
\s*\r?\n        # match remainder of line

(               # begin cap grp 4 (group name 1)
  [a-z]+        # match 1+ ltrs
  (?: [a-z]+)   # match 1 space, 1+ ltrs in non-cap grp
  *             # execute non-cap grp 0+ times
)               # end cap grp 4
.*\r?\n         # match remainder of line

(?:             # begin non-cap grp
  (             # begin cap grp 5 (opt. group name 2)
    [a-z]+      # match 1+ ltrs
    (?: [a-z]+) # match 1 space, 1+ ltrs in non-cap grp
    *           # execute non-cap grp 0+ times
  )             # end cap grp 5
  .*\r?\n       # match remainder of line
)               # end non-cap grp
?               # optionally match non-cap grp

(\d+)           # match 1+ digits in cap grp 6 (group id)

Я понимаю, что механизм регулярных выражений Python не поддерживает подпрограммы. К сожалению, использование подпрограмм значительно упростило бы регулярное выражение. Механизм PCRE (PHP) позволяет, например, заменять каждый экземпляр после первого из ([a-z]+(?: [a-z]+)) на ((?1)).

...