2

我最近开始使用 pyparsing,但遇到以下问题:有些数据按列组织,其中列数未知,此外,这样的部分可能在输入中出现多次。例如,请参见下面的代码。

# -*- coding: utf-8 -*-

from pyparsing import *
from decimal import Decimal

def convert_float(a):
    return Decimal(a[0].replace(',','.'))

def convert_int(a):
    return int(a[0])

NL = LineEnd().suppress()

dot = Literal('.')
dates = Combine(Word(nums,exact=2) + dot + Word(nums,exact=2) + dot + Word(nums,exact=4))
day_with_date = Word(alphas,exact=3).suppress() + dates

amount = ( Combine(OneOrMore(Word(nums)) + ',' + Word(nums),adjacent=False) + 
           Optional(Literal('EUR')).suppress() ).setParseAction(convert_float)
number = Word(nums).setParseAction(convert_int)

item_head = OneOrMore(Keyword('Item').suppress() + number)
item_det = Forward()
item_foot = Forward()

def defineColNumber(t):
    nbcols = len(t)#[0])
    item_det << Dict(Group(day_with_date('date') + Group(nbcols*amount)('data')))
    item_foot << Keyword('TOTAL').suppress() + Group(nbcols*amount)

sec = (item_head('it*').setParseAction(defineColNumber) + 
       Group(OneOrMore(item_det))('details*') + 
       item_foot('totals*'))

parser = OneOrMore(
             sec
         )
parser.ignore(NL)

out = """
                             Item 1             Item 2             Item 3
Sat 20.04.2013     3 126 375,00 EUR     115 297,00 EUR      67 830,00 EUR      
Fri 19.04.2013     1 641 019,20 EUR      82 476,00 EUR      48 759,00 EUR      
Thu 18.04.2013       548 481,10 EUR      46 383,00 EUR      29 810,00 EUR      
Wed 17.04.2013       397 396,70 EUR      42 712,00 EUR      26 812,00 EUR 
TOTAL              8 701 732,00 EUR   1 661 563,00 EUR   1 207 176,00 EUR

                             Item 4             Item 5
Sat 20.04.2013       126 375,00 EUR     215 297,00 EUR      
Fri 19.04.2013     2 641 019,20 EUR      32 476,00 EUR      
Thu 18.04.2013       548 481,10 EUR      56 383,00 EUR      
Wed 17.04.2013       397 396,70 EUR      42 712,00 EUR
TOTAL              2 701 732,00 EUR   1 663 563,00 EUR   

"""

p = parser.parseString(out, parseAll=True)
print p.dump()
print p.it
print p.details[0]['18.04.2013'].data[2]
print p.totals

目前例如 p.it 看起来[[1, 2, 3], [4, 5]] 我需要[1,2,3,4,5]的其他部分也是如此,所以p.details[0]['18.04.2013'].data[2]我可以这样做p.details['18.04.2013'].data[2]

我没有想法 - 是否可以以某种简单的方式加入结果,或者我需要使用其他功能更改 ParseResults?

感谢帮助。

顺便说一句——这段代码对解析日期、金额等有意义吗?

4

1 回答 1

1

这种对表格数据的解析是 pyparsing 的原始案例之一。恭喜您在解析非平凡的输入文本方面取得了进展!

与其尝试进行任何不自然的分组或诸如此类将解析的数据扭曲或组合到所需的数据结构中,不如在您获得解析结果并建立一个新的摘要结构时,我将其称为summary. 我们实际上是将数据累积到这个字典中,这强烈建议在找到新键时使用 defaultdict 来简化摘要的初始化。

from collections import defaultdict
summary = defaultdict(dict)

查看 中返回的当前结构p,您将获得项目标题和详细数据集,这些数据集收集到命名结果itdetails. 我们可以将它们压缩在一起以获取每个部分的标题和数据。然后对于详细信息中的每一行,我们将通过使用已解析的数据值压缩项目标题来制作详细值的字典。然后我们将更新由 键控的汇总值line.date

for items,details in zip(p.it,p.details):
    for line in details:
        summary[line.date[0]].update(dict(zip(items,line.data)))

完毕!看看我们积累了哪些key:

print summary.keys()

给出:

['20.04.2013', '18.04.2013', '17.04.2013', '19.04.2013']

打印为 '18.04.2013' 积累的数据:

print summary['18.04.2013']

给出:

{1: Decimal('548481.10'), 2: Decimal('46383.00'), 3: Decimal('29810.00'), 4: Decimal('548481.10'), 5: Decimal('56383.00')}
于 2013-06-07T12:49:38.173 回答