2009-09-14 4 views
3

Я хотел разобрать текстовый файл, содержащий неструктурированный текст. Мне нужно получить адрес, дату рождения, имя, пол и идентификатор.Анализ неструктурированного текста в Python

. 55 MORILLO ZONE VIII, 
BARANGAY ZONE VIII 
(POB.), LUISIANA, LAGROS 
F 
01/16/1952 
ALOMO, TERESITA CABALLES 
3412-00000-A1652TCA2 
12  
. 22 FABRICANTE ST. ZONE 
VIII LUISIANA LAGROS, 
BARANGAY ZONE VIII 
(POB.), LUISIANA, LAGROS 
M 
10/14/1967 
AMURAO, CALIXTO MANALO13 

В приведенном выше примере, первые 3 строки представляет собой адрес, линия с просто «F» является секс, то DOB бы линию после того, как «F», имя после DOB, идентификатор после имени, и нет. 12 под идентификатором - индекс/запись №.

Однако формат несовместим. Во второй группе адрес - 4 строки вместо 3 и индекс/запись нет. добавляется после имени (если у человека нет поля идентификатора).

Я хотел переписать текст в следующем формате:

name, ID, address, sex, DOB 

ответ

12

Вот первый удар по решению для пипарирования (easy-to-copy code at the pyparsing pastebin). Пройдите через отдельные части, в соответствии с чередующимися комментариями.

data = """\ 
. 55 MORILLO ZONE VIII, 
BARANGAY ZONE VIII 
(POB.), LUISIANA, LAGROS 
F 
01/16/1952 
ALOMO, TERESITA CABALLES 
3412-00000-A1652TCA2 
12 
. 22 FABRICANTE ST. ZONE 
VIII LUISIANA LAGROS, 
BARANGAY ZONE VIII 
(POB.), LUISIANA, LAGROS 
M 
10/14/1967 
AMURAO, CALIXTO MANALO13 
""" 

from pyparsing import LineEnd, oneOf, Word, nums, Combine, restOfLine, \ 
    alphanums, Suppress, empty, originalTextFor, OneOrMore, alphas, \ 
    Group, ZeroOrMore 

NL = LineEnd().suppress() 
gender = oneOf("M F") 
integer = Word(nums) 
date = Combine(integer + '/' + integer + '/' + integer) 

# define the simple line definitions 
gender_line = gender("sex") + NL 
dob_line = date("DOB") + NL 
name_line = restOfLine("name") + NL 
id_line = Word(alphanums+"-")("ID") + NL 
recnum_line = integer("recnum") + NL 

# define forms of address lines 
first_addr_line = Suppress('.') + empty + restOfLine + NL 
# a subsequent address line is any line that is not a gender definition 
subsq_addr_line = ~(gender_line) + restOfLine + NL 

# a line with a name and a recnum combined, if there is no ID 
name_recnum_line = originalTextFor(OneOrMore(Word(alphas+',')))("name") + \ 
    integer("recnum") + NL 

# defining the form of an overall record, either with or without an ID 
record = Group((first_addr_line + ZeroOrMore(subsq_addr_line))("address") + 
    gender_line + 
    dob_line + 
    ((name_line + 
     id_line + 
     recnum_line) | 
     name_recnum_line)) 

# parse data 
records = OneOrMore(record).parseString(data) 

# output the desired results (note that address is actually a list of lines) 
for rec in records: 
    if rec.ID: 
     print "%(name)s, %(ID)s, %(address)s, %(sex)s, %(DOB)s" % rec 
    else: 
     print "%(name)s, , %(address)s, %(sex)s, %(DOB)s" % rec 
print 

# how to access the individual fields of the parsed record 
for rec in records: 
    print rec.dump() 
    print rec.name, 'is', rec.sex 
    print 

Печать:

ALOMO, TERESITA CABALLES, 3412-00000-A1652TCA2, ['55 MORILLO ZONE VIII,', 'BARANGAY ZONE VIII', '(POB.), LUISIANA, LAGROS'], F, 01/16/1952 
AMURAO, CALIXTO MANALO, , ['22 FABRICANTE ST. ZONE', 'VIII LUISIANA LAGROS,', 'BARANGAY ZONE VIII', '(POB.), LUISIANA, LAGROS'], M, 10/14/1967 

['55 MORILLO ZONE VIII,', 'BARANGAY ZONE VIII', '(POB.), LUISIANA, LAGROS', 'F', '01/16/1952', 'ALOMO, TERESITA CABALLES', '3412-00000-A1652TCA2', '12'] 
- DOB: 01/16/1952 
- ID: 3412-00000-A1652TCA2 
- address: ['55 MORILLO ZONE VIII,', 'BARANGAY ZONE VIII', '(POB.), LUISIANA, LAGROS'] 
- name: ALOMO, TERESITA CABALLES 
- recnum: 12 
- sex: F 
ALOMO, TERESITA CABALLES is F 

['22 FABRICANTE ST. ZONE', 'VIII LUISIANA LAGROS,', 'BARANGAY ZONE VIII', '(POB.), LUISIANA, LAGROS', 'M', '10/14/1967', 'AMURAO, CALIXTO MANALO', '13'] 
- DOB: 10/14/1967 
- address: ['22 FABRICANTE ST. ZONE', 'VIII LUISIANA LAGROS,', 'BARANGAY ZONE VIII', '(POB.), LUISIANA, LAGROS'] 
- name: AMURAO, CALIXTO MANALO 
- recnum: 13 
- sex: M 
AMURAO, CALIXTO MANALO is M 
+0

Привет, Пол. Спасибо за решение! У меня есть строки, начинающиеся с «# | *», которые я хочу игнорировать/пропускать. Как мне это сделать? – Francis

+1

Вы имеете в виду, что они начинаются со строки «# | *»? Или что они начинаются с любого из этих персонажей? Если первый, определите комментарий как comment = "# | *" + restOfLine + NL; если второй определяет комментарий как comment = oneOf ("# | *") + restOfLine + NL. Затем выполните: record.ignore (комментарий) - easy-peasy! – PaulMcG

4

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

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

2

Возможно, вы можете сделать это с помощью регулярных выражений без особых трудностей. Если вы никогда не использовали их раньше, проверьте документацию на python, затем запустите redemo.py (на моем компьютере он находится в c: \ python26 \ Tools \ scripts).

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

import re 
re_entity_splitter = re.compile(r'^\.') 

entities = re_entity_splitter.split(open(textfile).read()) 

Обратите внимание, что точка должна быть экранированы (это символ подстановки по умолчанию). Обратите внимание также на r перед шаблоном. R обозначает формат «сырой строки», который оправдывает вас необходимостью избежать escape-символов, что приводит к так называемой «обратной косой чертой».

Как только у вас есть файл, разбитый на отдельных людей, выбор пола и даты рождения является быстрым. Используйте их:

re_gender  = re.compile(r'^[MF]') 
re_birth_Date = re.compile(r'\d\d/\d\d/\d\d') 

И уходите. Вы можете вставить плоский файл в демонстрационный GUI и поэкспериментировать с созданием шаблонов в соответствии с тем, что вам нужно. Вы его разобрали в кратчайшие сроки. Как только вы добьетесь этого, вы можете использовать имена символических групп (см. Документы) для быстрого и чистого выделения отдельных элементов.

+0

Благодарности. У меня уже есть опыт регулярных выражений. Как мне обращаться с адресной частью? Некоторые объекты имеют 3 или 4 строки. – Francis

+0

Как только вы разделите файл на список людей, для каждого человека я бы попробовал это: 1. разделите текст человека на список строк 2. для каждого списка людей, в то время как последний элемент в списке не " t соответствует re_gender, поместите элемент в конец списка. 3. Остальные элементы списка - это адрес. LST = person.splitlines() , пока не re_gender.search (LST [-1] .strip()): lst.pop() lst.pop() ADDRESS_LIST = LST – twneale

1

Вот кратковременная ручная работа.

f = open('data.txt') 

def process(file): 
    address = "" 

    for line in file: 
     if line == '': raise StopIteration 
     line = line.rstrip() # to ignore \n 
     if line in ('M','F'): 
      sex = line 
      break 
     else: 
      address += line 

    DOB = file.readline().rstrip() # to ignore \n 
    name = file.readline().rstrip() 

    if name[-1].isdigit(): 
     name = re.match(r'^([^\d]+)\d+', name).group(1) 
     ID = None 
    else: 
     ID = file.readline().rstrip() 
     file.readline() # ignore the record # 

    print (name, ID, address, sex, DOB) 

while True: 
    process(f) 
+0

Сбой на линии DOB = file.readline(). rstrip() с ошибкой ValueError: смешение итераций и методов чтения потеряют данные – Francis

+0

@Francis: в этом случае просто переведите цикл for в цикл while и используйте file.readline(). rstrip(). – Unknown

3

Это может быть излишним, но ведущие алгоритмы края машинного обучения для такого рода проблемы основаны на conditional random fields. Например, Accurate Information Extraction from Research Papers using Conditional Random Fields.

Существует программное обеспечение, которое упрощает обучение этих моделей. См. Mallet или CRF++.

Смежные вопросы