2015-11-16 27 views
2

所以我在這(標準)格式的數據文件:有道閱讀基於位置的文本文件

12455WE READ THIS    TOO796445 125997 554777  
22455 888AND THIS  TOO796445 125997 55477778 2 1 

人誰做了太多的COBOL大概因子評分起來。

每個字段都有一個固定的長度,我可以通過切片來讀取它。

我的問題是如何構建我的代碼,使其更靈活,並且不會使我使用硬編碼的偏移量切片? 我應該使用一類這樣的常量嗎?

編輯:

另外,在第一數(0-> 9總是存在)確定哪一個是固定長度的線的結構。 此外,該文件由確保有效性的第三方提供,因此我不需要檢查僅讀取它的格式。 大約有11種不同的線結構。

+0

是否有10層不同的可能的線結構,根據第一數字?不同的線路結構是否會相互不同?或者只有前幾個字段有所不同,所有後續字段保持不變,如示例中所示? –

+0

他們基本上所有的變化見https://www.febelfin.be/sites/default/files/Standard-CODA-2.3-EN.pdf 的格式 – maazza

+0

我看到只有一種方法,如下建議,創建多個記錄寬度結構,基於記錄的最初5位數代碼。請記住,標題記錄包含版本號,因此您可能必須根據數據版本允許不同的結構,或者您可能會發現在版本更改時無法解碼較舊的文件。我想問問問一個現場分隔符是多麼困難,但要求銀行改變什麼,是a)毫無意義,b)即使他們同意也需要幾年時間。 –

回答

1

創建一個列表寬度和一個例程,接受這個和一個索引列號作爲參數。該例程可以通過添加所有以前的列寬來計算切片的起始偏移量,併爲結束偏移量添加索引列的寬度。

+0

如果第一個數字決定了該行的結構,您認爲它仍然適用嗎? – maazza

+0

@maaza:我沒有看到有不同寬度列表的問題。這就是爲什麼我提出了一個普遍的例程。當然,完全取決於你如何選擇使用幾個寬度列表中的哪一個,但例程保持不變。 – usr2564301

1

您可以描述的格式列的寬度的列表,將其展開這樣的:

formats = [ 
    [1, ], 
    [1, 4, 28, 7, 7, 7], 
] 

def unfold(line): 
    lengths = formats[int(line[0])] 
    ends = [sum(lengths[0:n+1]) for n in range(len(lengths))] 
    return [line[s:e] for s,e in zip([0] + ends[:-1], ends)] 

lines = [ 
    "12455WE READ THIS    TOO796445 125997 554777", 
] 

for line in lines: 
    print unfold(line) 

編輯:更新的代碼,以更好地匹配什麼maazza要求在編輯的問題。這假設格式字符是一個整數,但它可以很容易地推廣到其他格式指示符。

3

我的建議是使用鍵入5位數行代碼的字典。字典中的每個值可以是字段偏移量(或(偏移量,寬度)元組)的列表,由字段位置索引。

如果您的字段有其名稱可能可以方便地使用類而不是列表來存儲字段偏移數據。但是,namedtuples在這裏可能會更好,因爲您可以通過其名稱或其字段位置訪問您的字段偏移數據,因此您可以獲得兩全其美的好處。

namedtuple s的實際實現的類,但定義一個新namedtuple型結構更加緊湊,創建一個明確的類定義,並namedtuples使用__slots__協議,所以他們採取了比使用__dict__對於一個普通的類RAM較少存儲它的屬性。


下面是使用namedtuples存儲的字段偏移量數據的一種方法。我並沒有聲稱下面的代碼是做這件事的最好方法,但它應該給你一些想法。

from collections import namedtuple 

#Create a namedtuple, `Fields`, containing all field names 
fieldnames = [ 
    'record_type', 
    'special', 
    'communication', 
    'id_number', 
    'transaction_code', 
    'amount', 
    'other', 
] 

Fields = namedtuple('Fields', fieldnames) 

#Some fake test data 
data = [ 
    #   1   2   3   4   5 
    #
    "12455WE READ THIS    TOO796445 125997 554777", 
    "22455 888AND THIS  TOO796445 125997 55477778 2 1", 
] 

#A dict to store the field (offset, width) data for each field in a record, 
#keyed by record type, which is always stored at (0, 5) 
offsets = {} 

#Some fake record structures 
offsets['12455'] = Fields(
    record_type=(0, 5), 
    special=None, 
    communication=(5, 28), 
    id_number=(33, 6), 
    transaction_code=(40, 6), 
    amount=(48, 6), 
    other=None) 

offsets['22455'] = Fields( 
    record_type=(0, 5), 
    special=(6, 3), 
    communication=(9, 18), 
    id_number=(27, 6), 
    transaction_code=(34, 6), 
    amount=(42, 8), 
    other=(51,3)) 

#Test. 
for row in data: 
    print row 
    #Get record type 
    rt = row[:5] 
    #Get field structure 
    fields = offsets[rt] 
    for name in fieldnames: 
     #Get field offset data by field name 
     t = getattr(fields, name) 
     if t is not None: 
      start, flen = t 
      stop = start + flen 
      data = row[start : stop]    
      print "%-16s ... %r" % (name, data) 
    print 

輸出

12455WE READ THIS    TOO796445 125997 554777 
record_type  ... '12455' 
communication ... 'WE READ THIS    TOO' 
id_number  ... '796445' 
transaction_code ... '125997' 
amount   ... '554777' 

22455 888AND THIS  TOO796445 125997 55477778 2 1 
record_type  ... '22455' 
special   ... '888' 
communication ... 'AND THIS  TOO' 
id_number  ... '796445' 
transaction_code ... '125997' 
amount   ... '55477778' 
other   ... '2 1' 
+0

你能告訴我一個namedtuple的例子嗎? – maazza

+0

@maazza:在鏈接的文檔中有幾個創建和使用namedtuples的例子。 –

+0

我讀過它但未能看到它如何應用於我的案例 – maazza