Разбор текстовых файлов в неправильных форматах - PullRequest
0 голосов
/ 01 июня 2011

У меня очень большой текстовый файл, который был создан путем преобразования PDF в текстовый формат с помощью утилиты XPDF 'pdftotext'. Документ содержит данные о заброшенных свойствах, которые я хотел бы иметь возможность анализировать в удобном для базы данных формате. Файл отформатирован следующим образом:

DOE JANE H                                        STATE         1994     0002       SAVINGS       52            33.99   0
                                                  EMPLOYEES                         ACCOUNTS
                                                  CREDIT UNION

                 SOMECITY      ZZ      12345

В общем, все записи выглядят так. Некоторые из них занимают одну дополнительную строку (с дополнительным пробелом перед строкой city / state / zip.

Чтобы сделать это еще лучше, текст не был преобразован равномерно. Каждая страница PDF преобразуется в «страницу» текстового файла, имеющего разную ширину столбца. Кроме того, данные иногда могут выглядеть так:

DOE JANE H      OR SOME OTHER OWNER           STATE         1994     0002       SAVINGS       52            33.99   0
                                              EMPLOYEES                         ACCOUNTS
                                              CREDIT UNION

                SOMECITY      ZZ      12345

Или, альтернативно, так:

DOE                                      STATE         1994     0002       SAVINGS       52            33.99   0
JANE                                     EMPLOYEES                         ACCOUNTS
H                                        CREDIT UNION

            SOMECITY      ZZ      12345

Итак, что я могу с этим поделать? Любая помощь приветствуется.

UPDATE:

Чтобы уточнить - я пытался разобрать это с помощью регулярных выражений и Perl, но безуспешно (я не смог найти приличный способ работы с кусками по 5 строк за раз, или с различными кусками в записи иногда занимают 6 строк). В своей лучшей попытке мне удалось разобрать только первую строку каждой записи, которая содержит только частичную информацию (часть или все имя, первая строка владельца, год отчета, тип свойства и т. Д.). ). В идеале я хотел бы иметь возможность получить всю информацию для записи, независимо от различных форматов. Язык программирования не имеет значения, поэтому подойдет любой подходящий инструмент для работы. Я надеялся получить некоторую информацию о различных вариантах синтаксического анализа файла, такого как этот, возможно, о различных инструментах или даже приложениях, которые занимаются такими проблемами.

1 Ответ

2 голосов
/ 01 июня 2011

Вот начало в Python.Нечто подобное может быть сделано в Perl.

col_start_pat = re.compile( r'\s+\s(?=\S)' )
for row in ( r.rstrip() for r in data.splitlines() ):
    if not row: continue
    def matches( row ):
        offset= 0
        for m in col_start_pat.finditer( row ):
            yield offset, row[offset:m.end(0)].rstrip()
            offset= m.end(0)
        yield offset, row[offset:].rstrip()
    columns= list( matches( row ) )
    if not columns: continue
    print( columns )

Это не делает всю работу.Он просто идентифицирует «поля» в каждой строке как последовательность кортежей, которые выглядят следующим образом.

[(0, 'DOE JANE H'), (50, 'STATE'), (64, '1994'), (73, '0002'), (84, 'SAVINGS'), (98, '52'), (112, '33.99'), (120, '0')]
[(0, ''), (50, 'EMPLOYEES'), (84, 'ACCOUNTS')]
[(0, ''), (50, 'CREDIT UNION')]
[(0, ''), (17, 'SOMECITY'), (31, 'ZZ'), (39, '12345')]
[(0, 'DOE JANE H'), (16, 'OR SOME OTHER OWNER'), (46, 'STATE'), (60, '1994'), (69, '0002'), (80, 'SAVINGS'), (94, '52'), (108, '33.99'), (116, '0')]
[(0, ''), (46, 'EMPLOYEES'), (80, 'ACCOUNTS')]
[(0, ''), (46, 'CREDIT UNION')]
[(0, ''), (16, 'SOMECITY'), (30, 'ZZ'), (38, '12345')]
[(0, 'DOE'), (41, 'STATE'), (55, '1994'), (64, '0002'), (75, 'SAVINGS'), (89, '52'), (103, '33.99'), (111, '0')]
[(0, 'JANE'), (41, 'EMPLOYEES'), (75, 'ACCOUNTS')]
[(0, 'H'), (41, 'CREDIT UNION')]
[(0, ''), (12, 'SOMECITY'), (26, 'ZZ'), (34, '12345')]

Следующая часть заключается в использовании номеров столбцов заголовка для идентификации формата, а затем сворачивания строк водин объект.


Расширение на это ...

pat1= [0, 50, 64, 73, 84, 98, 112, 120]
pat2= [0, 16, 46, 60, 69, 80, 94, 108, 116]
pat3= [0, 41, 55, 64, 75, 89, 103, 111]

def columns( data ):
    col_start_pat = re.compile( r'\s+\s(?=\S)' )
    for row in ( r.rstrip() for r in data.splitlines() ):
        if not row: continue
        def matches( row ):
            offset= 0
            for m in col_start_pat.finditer( row ):
                yield offset, row[offset:m.end(0)].rstrip()
                offset= m.end(0)
            yield offset, row[offset:].rstrip()
        columns= list( matches( row ) )
        yield columns

def row_groups( data ):
    columns_iter= columns(data)
    record= []
    for parsed in columns_iter:
        offsets= [ c[0] for c in parsed ]
        if offsets == pat1:
            if record: yield( format, record )
            format= 1
            record= []
        elif offsets == pat2:
            if record: yield( format, record )
            format= 2
            record= []
        elif offsets == pat3:
            if record: yield( format, record )
            format= 3
            record= []
        record.extend( parsed )
    yield( format, record )

for record in row_groups( data ):
    print( record )

Получает вам следующее:

(1, [(0, 'DOE JANE H'), (50, 'STATE'), (64, '1994'), (73, '0002'), (84, 'SAVINGS'), (98, '52'), (112, '33.99'), (120, '0'), (0, ''), (50, 'EMPLOYEES'), (84, 'ACCOUNTS'), (0, ''), (50, 'CREDIT UNION'), (0, ''), (17, 'SOMECITY'), (31, 'ZZ'), (39, '12345')])
(2, [(0, 'DOE JANE H'), (16, 'OR SOME OTHER OWNER'), (46, 'STATE'), (60, '1994'), (69, '0002'), (80, 'SAVINGS'), (94, '52'), (108, '33.99'), (116, '0'), (0, ''), (46, 'EMPLOYEES'), (80, 'ACCOUNTS'), (0, ''), (46, 'CREDIT UNION'), (0, ''), (16, 'SOMECITY'), (30, 'ZZ'), (38, '12345')])
(3, [(0, 'DOE'), (41, 'STATE'), (55, '1994'), (64, '0002'), (75, 'SAVINGS'), (89, '52'), (103, '33.99'), (111, '0'), (0, 'JANE'), (41, 'EMPLOYEES'), (75, 'ACCOUNTS'), (0, 'H'), (41, 'CREDIT UNION'), (0, ''), (12, 'SOMECITY'), (26, 'ZZ'), (34, '12345')])

Который содержит всю информацию;для этого нужна просто умная сборка.

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