4

したがって、この(標準化された)形式のデータを含むファイルがあります。

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

おそらく、cobol をやりすぎた誰かによって強化されたのでしょう。

各フィールドには固定長があり、行をスライスして読み取ることができます。

私の問題は、コードをより柔軟にし、スライスにハードコードされたオフセットを使用させないようにコードを構造化するにはどうすればよいかということです。そのような定数のクラスを使用する必要がありますか?

編集:

また、最初の数字 (0->9 は常に存在) は、固定長の行の構造を決定します。また、ファイルは有効性を保証するサードパーティによって提供されているため、形式を確認する必要はなく、読み取るだけです。約 11 の異なるライン構造があります。

4

3 に答える 3

3

私の提案は、5 桁の線種コードをキーにした辞書を使用することです。ディクショナリ内の各値は、フィールド オフセット (または (オフセット、幅) タプル) のリストであり、フィールド位置によってインデックスが付けられます。

フィールドに名前がある場合、リストの代わりにクラスを使用してフィールド オフセット データを格納すると便利な場合があります。ただし、namedtuples名前またはフィールド位置を介してフィールド オフセット データにアクセスできるため、ここではより良いかもしれません。そのため、両方の長所を活用できます。

namedtuples は実際にはクラスとして実装されますが、新しいnamedtuple型を定義することは、明示的なクラス定義を作成するよりもはるかにコンパクトでありnamedtuples、プロトコルを使用するため、属性を格納するために__slots__使用する通常のクラスよりも少ない RAM を使用します。__dict__


namedtuplesフィールド オフセット データを格納するために使用する 1 つの方法を次に示します。次のコードがこれを行うための最良の方法であると主張しているわけではありませんが、いくつかのアイデアが得られるはずです。

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
    #012345678901234567890123456789012345678901234567890123
    "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'
于 2015-11-16T10:50:19.890 に答える
1

のリストと、これとインデックス付きの列番号をパラメーターとして受け入れるルーチンを作成します。ルーチンは、以前のすべての列幅を追加してスライスの開始オフセットを計算し、終了オフセットのインデックス付き列の幅を追加できます。

于 2015-11-16T09:30:31.613 に答える