2016-05-16 4 views
0

ファイル(.csvまたは.txt)からテーブルを抽出する必要があります。ファイルがcsvであると仮定してください。 このファイルには異なるサイズ(500x5,200x3、...)あなたは私を助けてくださいでしファイルと異なるサイズの配列を抽出する

Book of sales du 01/01/2014 au 31/12/2050;;;;;;;;;;; 

Sales;;;;;;;;;;; 

Date;Invoice;Client;Txt;Price 

19/02/2015;1;Johnny;coloris: 002, taille: 54/18;82,03€ 

21/02/2015;2;Florian;coloris: 005PL, taille: 56/17;78,34€ 
Total;;;;10 700,74€ 

;;;;;;;;;;; 

Avoirs générés;;;;;;;;;;; 

Date;N° Avoir;Client 

04/03/2015;1;Johnny 

28/03/2015;2;Jacques-Elie 

Total;;698,45€ 

: は、私は私のファイルのデータベース

構造でそれらをロードするために、異なる配列でそれらを抽出する必要がありますか?

答えて

0

このデータを処理するには、単純なパーサーを作成する必要があります。

パーサーは小さなステートマシンです。現在の状態と次に表示される入力に応じて、新しい状態に移行します。状態間を移動するにつれて、入力を集めて何らかの木構造を作成します。あなたはパーサが通過する必要がある状態を記述するときに、各状態とそれを結ぶ線の円を描くことによってこれを視覚化することができます。状態間を移動するために必要な入力を各行に付けます。

あなたのデータは、日付範囲を持つヘッダ行を期待して、初期状態(待機中のヘッダ)に開始されます。

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")と ` ライン= [] :

+0

こんにちはナポリ、Thakあなた – Brice

0

は、私がこれを書いた返信

いただき、ありがとうございますお返事のためのtt.readlines()]

import re 
re.findall("Date..",content[3]) 

idx_date=[i for i, item in enumerate(content) if re.search('Date', item)] 
idx_total=[i for i, item in enumerate(content) if re.search('Total [^H^T]|TOTAL [^H^T]', item)] 
tab={} 
tit={} 
for i in range(len(idx_date)): 
tab[i]=pd.DataFrame([ sub.split(";") for sub in content[idx_date[i]+1:idx_total[i]] ], \ 
     columns=content[idx_date[i]].split(";") ) 
    tit[i]=content[idx_total[i]][6: content[idx_total[i]].index(";")-1 ]\ 
     .replace('des ','').upper().replace(' ','_') 

tab={ tit[key]: value for key,value in tab.items() } 

`

+0

フィールドが「日付」を含むように発生した場合、クライアントが作る」の場合は、例えば(問題に実行されますデートサービス)。テーブルセパレータで分割するほうがずっと安全だと思われます。 – Neapolitan

+0

'for date_i、total_i in zip(idx_date、idx_total)'はコードを少しきれいにします。 'tit [i]'を割り当てたときに 'title'を割り当てることができるので' i'は必要でなく、 'tab [i]'を割り当てたように 'tab [title]'を割り当てます。これはまた、ループの後で再構成された辞書を削除します。 – Neapolitan

関連する問題