このデータを処理するには、単純なパーサーを作成する必要があります。
パーサーは小さなステートマシンです。現在の状態と次に表示される入力に応じて、新しい状態に移行します。状態間を移動するにつれて、入力を集めて何らかの木構造を作成します。あなたはパーサが通過する必要がある状態を記述するときに、各状態とそれを結ぶ線の円を描くことによってこれを視覚化することができます。状態間を移動するために必要な入力を各行に付けます。
あなたのデータは、日付範囲を持つヘッダ行を期待して、初期状態(待機中のヘッダ)に開始されます。
Book of sales du 01/01/2014 au 31/12/2050;;;;;;;;;;;
あなたは、ラインを読むことが期待される形式と一致することを確認し、抽出して維持する必要があります次の状態(テーブルを待つ)に移動します。
テーブルの名前の後に11セミコロンが続くように見えます。例:あなたは、あなたが指定したテーブル名を持つ新しいテーブルを開始し、(フィールド名を期待して)状態に移動する必要がある11のセミコロンで終わる行を検出した場合
Sales;;;;;;;;;;;
。
フィールド名は、セミコロンで区切られた文字列です:
Date;Invoice;Client;Txt;Price
あなたは(処理データ)を、セミコロンのヘッダ行を分割するフィールド名を保存し、新しい状態に移動する必要があります。
あなたのデータは、セミコロンで区切られたフィールドの値であること、ヘッダとして実質的に同じである:
19/02/2015;1;Johnny;coloris: 002, taille: 54/18;82,03€
ここでも、あなたが読んで、分割して保存します。今回は、テーブルに複数のレコードがある可能性があるため、現在の状態(データの処理中)にとどまります。
テーブルの要約行が合計で、同じフィールドを持つ代わりに、この場合における日:
Total;;;;10 700,74€
ですから、「合計」にいる間(処理データ)で始まる行を見れば、あなたは状態(サマリー)に移行し、合計を保存します。セミコロンのラインである
(要約)から、あなたは(エンドテーブル)に移行し、:
;;;;;;;;;;;
それとも、これは空のテーブルで、すべてのテーブルは、セミコロンで終わりではありません。あなたのサンプルのデータセットは2つのテーブルしか持っていないので、私は理解できません。ファイルの最後に2つのテーブルがあります。
処理(終了表)後、次の表の準備ができて、(待機中の表)に戻ります。代わりにファイルの終わりが表示される場合は、(最終状態)に遷移し、解析が完了しています。
ヘッダー、データ、要約の行はすべて基本的に同じ構造であるため、単一の状態(処理データ)に折り畳むことができ、処理が完了した後、テーブルの最初と最後の行を特別に扱うことができますそれらは容易に見つけることができるからである。このパーサはパーサーを簡単にしてデバッグするのが簡単です。
同様に、空の表の概念を導入すると、(終了表)状態が不要なため、パーサーをさらに簡略化できます。ヘッダー、データ、または要約のない空のテーブルの先頭として扱います。解析が完了したら空のテーブルを無視するのに十分なほど簡単です。さらに、空のテーブルの後で最初のテーブルが開始されるので、(データの処理)状態から始め、すべてがうまくいくようにすることができます。
入力内の各行間の空白行(おそらくキャリッジリターン+ウィンドウからの改行)は取り除くことができます。それを一緒に置く
、パーサは次のようになります。
このもう少しニシキヘビ作る
with open file:
# transition to (awaiting header)
read header
# transition to (processing data)
current table = empty
for each line:
# strip blank
if blank: # blank does not change state
continue
if new table line:
# transition to (new table)
save current table if any
make new table and set it to current table
# transition to (processing data)
else:
# transition to (processing data)
split line into data columns
# stay in (processing data)
save current table if any
# transition to (final state)
:
tables = []
with open(filename) as file:
line = file.readline()
start_date, end_date = line[17:27], line[31:41]
table_name, table_rows = "", [] # pretend we start with a blank table
for line in file: # reads lines one at a time until the end
line = line.strip() # remove linefeed from end of line
if not line: # check for blank line
continue
if line.endswith(';'*11): # line ends with 11 semicolons
# save the existing table; the first table will be blank
tables.append((table_name, table_rows))
table_name = line[:-11] # name is all but the last 11 semicolons
table_rows = []
else:
fields = line.split(';')
table_rows.append(fields)
# save the current table
table.append((table_name, table_rows))
あなたは今、(それらのいくつかは空でもよい)テーブルのリストを持っている必要があります。
# maybe record start_date, end_date
# process each table
for table_name, table_rows in tables:
if not table_rows: # table is blank
continue
fields = table_rows[0]
if table_rows[-1][0] == "Total":
rows = table_rows[1:-1]
summary = table_rows[-1]
else:
rows = table_rows[1:]
summary = None
save_table(table_name, fields, rows, summary)
このパーサーは簡単に始まりました。私たちは簡単にするためにいくつかのショートカットを使用しました。
言語は少し複雑だった場合、私たちはより抽象的な形でそれを残しているだろう:
state = 0
for line in file:
if state == 0:
if line matches transition from 0 to 0:
state = 0
save line data for state 0
elif line matches transition from 0 to 1:
state = 1
save line data for state 1
elif line matches transition from 0 to 2:
...
elif state == 1:
if line matches transition from 1 to 0:
state = 0
save line data for state 0
elif line matches transition from 1 to 1:
state = 1
save line data for state 1
elif line matches transition from 1 to 2:
...
elif state == 2:
...
この記事ではアイデアは、あなたが処理する必要があるデータの多くをカバーします。
深い入れ子構造のより複雑なデータ形式の場合、開始構造と終了構造を一致させる必要がある場合は、pyparsingなどの実際のパーサを使用する必要があります。かっこ付きの簡単な数式表現でも、パーサーツールなしでは実行が困難です。にラインのため) コンテンツ= [line.strip(:TTとしてオープン(パス+ "CaParArticle.csv")と ` ライン= [] :
こんにちはナポリ、Thakあなた – Brice