2016-07-12 8 views
0

私はPythonには新しく、ログファイルを解析するのが難しいです。私はどのように私は最もPythonicの方法で以下を達成することができるか理解するのを助けてくれますか?Pythonでテキストを再フォーマットする

----- Log Entry 5 ----- 
Time  : 2016-07-12 09:00:00 
Animal  : Brown Bear 
Bird  : White Owl 
Fish  : Salmon 


----- Log Entry 6 ----- 
Time  : 2016-07-12 09:00:00 
Animal  : Brown Bear 
Bird  : Parrot 
Fish  : Tuna 


----- Log Entry 7 ----- 
Time  : 2016-07-12 09:00:00 
Animal  : Lion 
Bird  : White Owl 
Fish  : Sword Fish 


----- Log Entry 8 ----- 
Time  : 2016-07-12 09:15:00 
Animal  : Lion 
Bird  : White Owl 
Fish  : Sword Fish 

所望の出力1:私は以下のように見えるために、ログを再フォーマットしたいと思います:

Time: 2016-07-12 09:00:00 Animal: Brown Bear Bird: White Owl Fish : Salmon 
Time: 2016-07-12 09:00:00 Animal: Brown Bear Bird: Parrot  Fish : Tuna 
Time: 2016-07-12 09:00:00 Animal: Lion  Bird: White Owl Fish : Sword Fish 
Time: 2016-07-12 09:15:00 Animal: Lion  Bird: White Owl Fish : Sword Fish 

所望の出力2:その後、私は、タイムスタンプを照会して取得する機能を持っているしたいと思いますカウントの要約:

Time: 2016-07-12 09:00:00 
Name:  Count: 
Brown Bear 2 
Lion  1 
White Owl 2 
Parrot  1 
Salmon  1 
Tuna  1 
Sword Fish 1 

Time: 2016-07-12 09:15:00 
Name:  Count: 
Lion  1 
White Owl 1 
Sword Fish 1 

マイコードこれまで:

import os, sys, time, re, collections, subprocess 

show_cmd = 'cat question | egrep -v \'^$|=|Log\' | awk \'ORS=NR%4?FS:RS\' | grep Time' 
log = (subprocess.check_output(show_cmd, shell=True).decode('utf-8')) 

def time_field(): 
    logRegex = re.compile(r'Time\s*:.*\d\d\d-\d\d-\d\d\s\d\d:\d\d') 
    log_parsed = (logRegex.findall(log)) 
    a = (str(log_parsed).replace(' ', '')) 
    a = ((' ' + a[1:-1]).split(',')) 
    for i in a: 
     print(i) 

time_field() 
+4

これまでに何を試しましたか?現在の実装ではどのような困難がありますか?あなたは最新のコードの試みの[mcve]を提供していただけますか? – idjaw

+0

何らかの方法でファイルを読み込めましたか? – depperm

+0

は期待どおりの出力を示していますか、それともdataformatにミラーリングされているはずですか? – patrick

答えて

1

これを実行する方法はたくさんあります。個人的には、正規表現を使用することは避けたいと思いますが、これはおそらく効率的ではなく、表現が面倒で柔軟性に欠けるからです。ここに私が思い付いたものです:

class Entry: 
    def __init__(self): 
     self.time = None 
     self.animal = None 
     self.bird = None 
     self.fish = None 

    def __repr__(self): 
     fmt = "{0} {1} {2} {3}".format(
      "Time: {time: <{width}}", 
      "Animal: {animal: <{width}}", 
      "Bird: {bird: <{width}}", 
      "Fish: {fish: <{width}}") 
     return fmt.format(
      time=self.time, animal=self.animal, 
      bird=self.bird, fish=self.fish, 
      width=12) 

    def __radd__(self, other): 
      return self.__add__(other) 

    def __add__(self, other): 
     if type(other) == dict: 
      for i in [self.animal, self.bird, self.fish]: 
       if i in other: other[i] += 1 
       else: other[i] = 1 
      return other 
     elif type(other) == Entry: 
      return self.__add__({}) + other 
     else: 
      return self.__add__({}) 

def parse_log(path): 
    def extract(line): 
     start = line.find(':') + 1 
     return line[start:].strip() 

    entries = [] 
    entry = None 
    with open(path, 'r') as f: 
     for line in f.readlines(): 
      if line.startswith('-----'): 
       if entry: entries.append(entry) 
       entry = Entry() 
      elif line.startswith('Time'): 
       entry.time = extract(line) 
      elif line.startswith('Animal'): 
       entry.animal = extract(line) 
      elif line.startswith('Bird'): 
       entry.bird = extract(line) 
      elif line.startswith('Fish'): 
       entry.fish = extract(line) 

     if entry: entries.append(entry) 

    return entries 


def print_output_1(entries): 
    for entry in entries: 
     print entry 

def print_output_2(entries, time): 
    animals = sum([e for e in entries if e.time == time]) 

    print "Time: {0}".format(time) 
    print "Name:  Count:" 
    for animal, count in animals.items(): 
     print "{animal: <{width}} {count}".format(
       animal=animal, count=count, width=12) 


logPath = 'log.log' 
time = '2016-07-12 09:15:00' 
entries = parse_log(logPath) 

print_output_1(entries) 
print "" 
print_output_2(entries, time) 

出力(log.logあなたが与えた入力と一致していることを与えられた)は、次のとおりです。

Time: 2016-07-12 09:00:00 Animal: Brown Bear Bird: White Owl Fish: Salmon 
Time: 2016-07-12 09:00:00 Animal: Brown Bear Bird: Parrot  Fish: Tuna 
Time: 2016-07-12 09:00:00 Animal: Lion   Bird: White Owl Fish: Sword Fish 
Time: 2016-07-12 09:15:00 Animal: Lion   Bird: White Owl Fish: Sword Fish 

Time: 2016-07-12 09:15:00 
Name:  Count: 
White Owl 1 
Sword Fish 1 
Lion   1 

このコードが機能する方法は、私たちに有利にオブジェクト指向プログラミングを使用することですログエントリを格納し、特定の形式でログエントリを表現し、特定のプロパティに従ってログエントリを結合するといった作業を単純化する必要があります。

まず、Entryオブジェクトとそのプロパティ(self.timeself.animalself.birdself.fish)は、ログ内のエントリを表していることに注意してください。プロパティに格納されている情報が正しいと仮定すると、その情報を書式設定された文字列として表すメソッドを作成できます。メソッド__repr__()は、Pythonがオブジェクトの文字列表現を望んでいるときに呼び出されるので、このコードを置くのが良い場所のようです。このメソッドにはformat関数が多用されていますが、formatのpythonドキュメントを閲覧した後の動作ははっきりしているはずです。

指定した2番目の出力を取得するには、これらのエントリオブジェクトを組み合わせる方法が必要です。これは多くの方法で行うことができ、私がやったやり方は必ずしも最良ではありません。私は、オブジェクトに+演算子が使用されたときに呼び出される__radd__()__add__()メソッドを使用しました。これにより、コードentry1 + entry2またはsum([entry1, entry2])を使用して、両方の項目の動物の合計を得ることができます。しかし、Entryクラスは、任意の情報を含むことができないため、合計の結果を格納するために使用することはできません。代わりに、私はオブジェクトを合計した結果にdictオブジェクトを使用することを選択しました。 2つ以上のオブジェクトを合計するには、Entryのオブジェクトは、Entry + Entry + Entryの結果がdict + Entryであるため、のオブジェクトをdictのオブジェクトと合計できる必要があります。

__add__()機能は、オブジェクトが追加されているオブジェクトがdictオブジェクトであるかどうかをチェックします。この場合、エントリ内の各動物が既にdictに存在するかどうかをチェックします。もしそうでなければ、動物をキーとして追加します。それ以外の場合は、そのキーの値をインクリメントします。 __radd__()は、特殊な状況で使用される点を除いて、__add__()に似ています。詳細については、Pythonのドキュメントを参照してください。オブジェクトがEntryある場合、コードは各Entry物体からの動物のすべてを収集し、その情報からdictを作成するために書かれたかもしれない場合には

が、dictEntryを追加するためのコードが既に存在するので1つのオブジェクトを空のdictに追加してから、結果としてdictをもう1つのEntryオブジェクトに追加する方が簡単です。

その他のオブジェクトの場合、Entryは、dict自身の説明、または空のdictが追加されたものを返します。

すべてのツールは、前述の目標を達成するために存在します。所望の出力1と一致するEntryの文字列表現を得るには、print entryまたはstrrepr = str(entry)が必要です。所望の出力2を得るために、もう少し作業が必要ですが、同じself.timeプロパティを持つすべてのエントリを合計し、結果のdictを表示するだけです。

最後の部分は、ログを解析してEntryオブジェクトのリストを作成することです。このコードは、ログを1行ずつ表示し、Entryに情報を入力します。私はこれがかなり簡単だと思っていますが、それが理にかなっていなければ、自由に質問することができます。

+0

これは私が探していたものを正確に達成しました!正直言って、私はあなたの方法を試して理解するために深刻な時間を費やす必要があります。私はPythonの初心者ですが、このフォーマットのログをたくさん扱うので、これは私にとって素晴らしいリファレンスです。迅速な返信とサポートをありがとうございます! – MBasith

+0

私はうまくいけばそれをより明確にするコードの説明を追加しました。この回答があなたのニーズを満たしている場合は、それを正しいものとして自由に記入してください。 – Alden

+0

説明のためにAldenに感謝します。それはとても役に立ちました! – MBasith

関連する問題