簡體   English   中英

使用Python解析基於塊的程序輸出

[英]Parsing blockbased program output using Python

我正在嘗試使用Python解析統計程序( Mplus )的輸出。

輸出的格式( 此處示例 )以塊,子塊,列等結構,其中空格和分隔符非常重要。 取決於例如。 選項要求您在此處或此處獲得附加的(子)塊或列。

使用正則表達式來解決這個問題一直是PITA,而且完全無法維護。 我一直在研究解析器作為一種更強大的解決方案,但是

  1. 所有可能的工具和方法都有點不知所措
  2. 給人的印象是它們不太適合這種輸出。

例如,LEPL有一種稱為行感知的解析 ,它似乎朝着正確的方向(空白,塊等)運行,但仍適合解析編程語法,而不是輸出。

建議朝哪個方向看。

根據您的示例,您擁有一堆不同的嵌套子格式,可以很容易地對其進行單獨解析。 令人不知所措的是,格式的數量巨大,而且它們可以以不同的方式嵌套。

在最低級別上,您在一行上有一組用空格分隔的值。 這些線組合成塊,而這些塊如何相互組合和嵌套是復雜的部分。 這種類型的輸出是專為人類閱讀而設計的,決不會被“刮”回機器可讀的形式。

首先,我將與軟件的作者聯系,並確定是否存在其他可用的輸出格式,例如XML或CSV。 如果正確完成(即不僅是包裝在笨拙的XML中的打印格式,或者用逗號替換空白),這將更容易處理。 如果不這樣做,我將嘗試提出格式的分層列表以及它們如何嵌套。 例如,

  1. ESTIMATED SAMPLE STATISTICS開始一個塊
  2. 在該塊中, MEANS/INTERCEPTS/THRESHOLDS開始一個嵌套塊
  3. 接下來的兩行是一組列標題
  4. 隨后是一行(或多行?)數據,帶有行標題和數據值

等等。 如果分別解決每個問題,您會發現它很繁瑣但並不復雜。 將上述每個步驟都視為測試輸入以查看其是否匹配的模塊,然后調用其他模塊以進一步測試可能在“內部”發生的事情,如果發現不匹配的內容則回溯。 t符合您的期望(順便說一下,這稱為“遞歸”)。

請注意,無論如何,您都必須執行類似的操作,以便構建可以在其上操作的數據的內存版本(“數據模型”)。

是的,這很難解析。 但是,您實際上並不需要很多正則表達式。 普通split可能足以將本文檔分為可管理的字符串序列。

這些就是我所說的“標題”文本塊。 您有標題,一行“-”,然后是數據。

您要做的是將“頭身”結構折疊到生成單個字典的生成器函數中。

def get_means_intecepts_thresholds( source_iter ):
    """Precondition: Current line is a "MEANS/INTERCEPTS/THRESHOLDS" line"""
    head= source_iter.next().strip().split()
    junk= source_iter.next().strip()
    assert set( junk ) == set( [' ','-'] )
    for line in source_iter:
        if len(line.strip()) == 0: continue
        if line.strip() == "SLOPES": break
        raw_data= line.strip().split()
        data = dict( zip( head, map( float, raw_data[1:] ) ) )
        yield int(raw_data[0]), data 

def get_slopes( source_iter ):
    """Precondition: Current line is a "SLOPES" line"""
    head= source_iter.next().strip().split()
    junk= source_iter.next().strip()
    assert set( junk ) == set( [' ','-'] )
    for line in source_iter:
        if len(line.strip()) == 0: continue
        if line.strip() == "SLOPES": break
        raw_data= line.strip().split() )
        data = dict( zip( head, map( float, raw_data[1:] ) ) )
        yield raw_data[0], data

關鍵是要通過一組操作來消耗頭部和垃圾。

然后使用一組不同的操作消耗隨后的數據行。

由於這些是生成器,因此可以將它們與其他操作結合使用。

def get_estimated_sample_statistics( source_iter ):
    """Precondition: at the ESTIMATED SAMPLE STATISTICS line"""
    for line in source_iter:
        if len(line.strip()) == 0: continue
    assert line.strip() == "MEANS/INTERCEPTS/THRESHOLDS"
    for data in get_means_intercepts_thresholds( source_iter ):
        yield data
    while True:
        if len(line.strip()) == 0: continue
        if line.strip() != "SLOPES": break
        for data in get_slopes( source_iter ): 
            yield data

這樣的事情可能比正則表達式更好。

我的建議是將線條粗略地按摩成更有用的形式。 這是對您的數據進行的一些實驗:

from __future__ import print_function
from itertools import groupby
import string
counter = 0

statslist = [ statsblocks.split('\n')
            for statsblocks in  open('mlab.txt').read().split('\n\n')
            ]
print(len(statslist), 'blocks')

def blockcounter(line):
    global counter
    if not line[0]:
        counter += 1
    return counter

blocklist = [ [block, list(stats)] for block, stats in groupby(statslist, blockcounter)]

for blockno,block in enumerate(blocklist):
    print(120 * '=')
    for itemno,line in enumerate(block[1:][0]):
        if len(line)<4 and any(line[-1].endswith(c) for c in string.letters) :
            print('\n** DATA %i, HEADER (%r)**' % (blockno,line[-1]))
        else:
            print('\n** DATA %i, item %i, length %i **' % (blockno, itemno, len(line)))
        for ind,subdata in enumerate(line):
            if '___' in subdata:
                print(' *** Numeric data starts: ***')
            else:
                if 6 < len(subdata)<16:
                    print( '** TYPE: %s **' % subdata)
                print('%3i : %s' %( ind, subdata))

您可以嘗試PyParsing 它使您能夠為要解析的內容編寫語法。 除了解析編程語言外,它還有其他示例。 但是我同意吉姆·加里森(Jim Garrison)的觀點,您的案子似乎並不需要真正的解析器,因為編寫語法會很麻煩。 我會嘗試蠻力解決方案,例如在空格處分割線。 這不是萬無一失的,但是我們可以假設輸出是正確的,因此,如果一行有n個標題,則下一行將恰好具有n個值。

事實證明,像這樣的表格程序輸出是我最早的pyparsing應用程序之一。 不幸的是,該確切示例處理了我無法發布的專有格式,但此處發布了一個類似示例: http : //pyparsing.wikispaces.com/file/view/dictExample2.py

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM