2017-09-27 11 views
0

"start"と "end"キーワードの間に関連するデータ(行x列)のみが表示されるテキストファイルがあります。下記参照。これらのデータサブセットを抽出できるコードを記述したいと思います。行が "start"とデータで始まり、それに続く "end"キーワードが続かない場合、そのデータは無視します。以下の私の例では、data1とdata3は関連していますが、data2は "start"と "end"キーワードで囲まれていないためNOTです。Pythonのテキストデータファイルからデータサブセットを抽出する方法

start 
data1 (matrix of data) /relevant because data1 is enclosed by "start" and "end" 
end 
start 
data2 (matrix of data) /not relevant because there is no "end" 
. 
start 
data3 (matrix of data) /relevant for same reason as for data1 
end 
. 
. 
and so on 

私は私で始まると考えていた:

with open(file_path,'r') as file: 

    text = file.readlines() 
    start_indexes = [] 
    end_indexes = [] 

    for i, line in enumerate(text): 
     if line.startswith('start'): 
      start_indexes.append(i) 
     elif line.startswith('end'): 
      end_indexes.append(i) 

    for i in range(len(start_indexes)): 
     for j in range(len(end_indexes)): 
      if (start_indexes[i] < end_indexes[j] < start_indexes[i+1]): 
       print(start_indexes[i],end_indexes[j]) 

上記のコードは私に開始行番号と関連するデータがある終了行番号の両方を提供します。ここで私は多少立ち往生しています。どのように関連するデータを引き出すのですか?以下の私の例では、data1、data3となります。私は問題に「正しい」方法で近づいていますか?私はパンダに頼るべきですか?もっと効率的で直接的な方法がありますか?

+0

は常にエーテルライン形式です: 'スタート。データ; startまたはstart;データ;終わり?入力例の期待出力を投稿してください。 – wwii

答えて

0

ネストされたForループ?

開始範囲と終了範囲のすべての組み合わせを実行しています。同じデータに対応するものだけが必要です。

このような何かを持つループのためにあなたを交換してください:

for start, end in zip(start_indexes, end_indexes): 
    print(text[start + 1:end]) 

zip(a, b, ...)本質的[(a[0], b[0], ...), (a[1], b[1], ...), ...]を与え、a, b, ...の列を持つ新しいリストを返します。 start_indexes, end_indexesの各列には、対応する開始値と終了値が表示されます。次に、リストスライスアクセスを使用して、その行のデータを取得します。

+0

ありがとうございます。私はzipを少し良く理解する必要がありますが、start_indexesとend_indexesは長さの異なるリストです。データの塊は常に「開始」と「終了」で囲まれているわけではありません。テストが成功した場合にのみ、データは "開始"と "終了"で囲まれます。データファイルに不成功のテストがある場合は、「開始」に続いて不完全なデータが続き、その後に「終了」が続きますが、2回目のテストが開始される別の「開始」が続きます。 2回目の試行が成功すると、最後に「終了」が表示されます。 – Murchak

+0

@Murchak 'zip'は常に方形行列を返します。 – HyperNeutrino

0

ファイルを順番に読むことで別の方法を使用します(これは、 "開始" - "終了"ブロックのデータが大きすぎないと仮定しています)。私はdata変数を作成して、現在のブロックのデータを(関連するかどうかにかかわらず)収集し、stateの状態遷移を持つ変数を収集します。

いくつかの擬似Pythonの:

if state == OUTSIDE_BLOCK and line.startswith('start'): 
    state = INSIDE_BLOCK 
elif state == INSIDE_BLOCK and <line contains data>: 
    <Add to data variable> 
elif state == INSIDE_BLOCK and line.startswith('end'): 
    state = OUTSIDE_BLOCK 
    <Process collected data> 
elif state == INSIDE_BLOCK and line.startswith('start'): 
    <Throw away possibly collected data because it was irrelevant> 
0

私は個人的には正規表現を感じるような状況に対処するための最良の方法である:

import re woof0='''start data1 (matrix of data) /relevant because data1 is enclosed by "start" and "end" end start data2 (matrix of data) /not relevant because there is no "end" . start data3 (matrix of data) /relevant for same reason as for data1 end . . and so on ''' re.findall(r'start(\sdata.*|\Sdata.*)\nend',woof0)

出力:

['\ndata1 (matrix of data) /relevant because data1 is enclosed by "start" and "end"', '\ndata3 (matrix of data) /relevant for same reason as for data1']

+0

OPは、 'start'の後に' data'とそれに続く 'end'が*取り込まれる*テキストではないと指定されています。 – wwii

+0

ありがとうGaurav。私はあなたがデータの構造を誤解しているかもしれないと思います。データ部分には単語データがありません。これは、各行(行)が観測であり、各行に多数の列(属性)が含まれている任意の数の行です。私は正規表現がどのように役立つか分かりません。 – Murchak

+0

データは一貫した形式、つまりCSVまたはスペースで区切られて表示されますか? –

0

セットアップ:

s = '''start 
data1 (matrix of data) /relevant because data1 is enclosed by "start" and "end" 
end 
start 
data2 (matrix of data) /not relevant because there is no "end" 
start 
data3 (matrix of data) /relevant for same reason as for data1 
end 
start 
data4 blah 
''' 
import io 
f = io.StringIO(s) 

ファイルを使用して一回反復、それぞれの行で始まるものをテストします。サブリストに有効なデータ・ブロックを配置して、結果のリストにそれらを追加するために必要なロジックを把握...

result = [] 
sub = [] 

for line in f: 
    if line.startswith('start'): 
     # possible new data block 
     if sub: 
      # if it isn't empty it must contain 
      # a start --> data block with no end 
      result.append(sub) 
      sub = [] 
     sub = [line] 
    elif line.startswith('end'): 
     # start over 
     sub = [] 
    elif line.startswith('data'): 
     sub.append(line) 
    else: 
     # for lines that don't startwith data, start or end - if any 
     sub.append(line) 

if sub: 
    # start --> data --> EOF or end of string 
    result.append(sub) 
関連する問題