从文本文件中提取节名称和起始页面

时间:2015-02-14 13:45:26

标签: python regex

我有一个input text file看起来像这样(" ......"实际上并不在原文中,但我用它来忽略一些冗长且可能不相关的文字; ^ L& #34;表示每个页面的开头(注意:" ^ L"键入为控制字符,而不是字符" ^"和字符" L") ):

(Begin text)

.. A language ...

^LIntroduction

6

A preferable alternative is ...

1.2.1 Abstraction by Parameters 
Abstraction allows us, ...

^L1.2 Abstraction

7

and ...

1.2.2 Abstraction by Specification 
... ...
^LAn Overview of CLU

14

In addition to ...

2.1.2 Type Checking
...

(End text)

所需的输出是:

1.2.1 Abstraction by Parameters 6    
1.2.2 Abstraction by Specification 7    
2.1.2 Type Checking 14

我想要做的是提取第三级部分名称它们出现的页码

  • 第三级部分名称始终显示在一行中。
  • 显示第三级部分名称的页码是第一个出现在一行中的数字,紧接在最后一个" ^ L"在节名之前。

我想知道如何用Python编写程序来实现这一目标?

这是我到目前为止所想的:

  • 匹配第三级部分名称的正则​​表达式模式为^\s*\d+\.\d+\.\d+.*\n
  • 每页
  • ," ^ L"表示页面的开头(注意:" ^ L"键入为控制字符,而不是字符" ^"和字符" L")。匹配部分的正则表达式模式来自" ^ L"到页面的页码^^L.*\n.*^\s*\d+\s*\n

我仍然不确定如何继续。谢谢你的启发!

2 个答案:

答案 0 :(得分:1)

您需要分隔的字符是\x0C / ^L / chr(12),即Page Break个字符。

<强> Demo

迭代方法

import re

def foo(lines):
    name = ''
    pages = []
    page_break_char = chr(0xC)

    for line in lines:

        if re.match('^\s*\d+\.\d+\.\d+.*', line):
            name = line
        elif re.match('^\d+$', line):
            pages.append(line)
        elif page_break_char in line:

            if name:
                yield name, pages

            del pages[:]

    if name:
        yield name, pages

<强>使用

text = '''

.. A language ...

\x0CIntroduction

6

A preferable alternative is ...

1.2.1 Abstraction by Parameters 
Abstraction allows us, ...

\x0C1.2 Abstraction

7

and ...

1.2.2 Abstraction by Specification 
... ...
\x0CAn Overview of CLU

14

In addition to ...

2.1.2 Type Checking ...

'''

lines = text.split('\n')
for name, pages in foo(lines):
    print name, ' '.join(pages)

<强>输出

enter image description here


在线演示

https://ideone.com/fH2yzm

答案 1 :(得分:1)

你必须了解文本 - 我需要仔细检查以制作这个。页码看起来像 - FormFeedPageNoLineFeedLineFeedPageNoLineFeed,并且页面上可以有多个第三级标题,所以从正则表达式开始,将提取整个页面并捕获页码

pages = re.compile(r'[\n\f](\d+)\n.*?(?=[\n\f](\d+)\n)', flags = re.DOTALL | re.MULTILINE)

然后在每个页面中搜索第三级标题并将它们放在一起。

third_level = re.compile('\n(\d+\.\d+\.\d+[^\n]*)')
for page in pages.finditer(s):
    page_no = page.group(1)
    for item in third_level.finditer(page.group()):
        print '{}\t{}'.format(item.group(1), page_no)

这产生了54个第三级标题。不幸的是,它是您的文字所独有的。在我弄清楚这一点的时候,我可以用一个好的文本编辑器半手动提取信息,这个编辑器可以进行正则表达式搜索(这就是我做出来解决它并验证它的方法)。

您可以优化pages - .*?与前瞻断言相结合。


编辑以提取第一级和第二级标题,然后与第三级标题结合使用。 OP文件的唯一标识stuff.txt

import re
with open('stuff.txt') as f:
    s = f.read()

提取内容和附录信息,附录分开提取以简化合并

content_item = re.compile('\d+\.?\d*? [^\n]*')
appendix_item = re.compile('Appendix[^\n]*|[ABC]\.[^\n]*')

# Indices to limit the contents search
content_start = re.search('\f\fContents', s).span()[1]
content_end = re.search('\f\fPreface', s).span()[0]

content_items = content_item.findall(s, content_start, content_end)
appendices = appendix_item.findall(s, content_start, content_end)

现在找到所有第三级标题和页码 - 与上面相同,但存储在列表中,

third_level = re.compile('\n(\d+\.\d+\.\d+[^\n]*)')
pages = re.compile(r'[\n\f](\d+)\n.*?(?=[\n\f](\d+)\n)', flags = re.DOTALL | re.MULTILINE)

third_levels = list()

for page in pages.finditer(s, content_end):
    page_no = page.group(1)
    for item in third_level.finditer(page.group()):
        third_levels.append('{}\t{}'.format(item.group(1), page_no))

合并内容和third_level标题,排序并添加附录标题。

a = content_items + third_levels

def key(item):
    '''Extract digits from the beginning of item for a sort key.

    item is a string
    >>> key('1 ABC')
    (1, None, None)
    >>> key('1.2 ABC')
    (1, 2, None)
    >>> key('1.2.3 ABC')
    (1, 2, 3)
    >>>
    '''
    item = item.split()
    item = item[0].split('.')
    a, b, c = None, None, None
    try:
        a = int(item[0])
    except ValueError as e:
        pass
    try:
        b = int(item[1])
    except IndexError as e:
        pass
    try:
        c = int(item[2])
    except IndexError as e:
        pass
    return a, b, c

a.sort(key = key)
a.extend(appendices)