0

ループに関するヘルプ、またはこれを行うためのより良い方法が必要です。答えは明白かもしれませんが、私はここに来たばかりで、今精神的なブロックを感じています: 私はこのようなログファイルを持っていて、同じ ID を持つすべての行を一致させようとしています: 後で値を比較できるように一致した ID。最初の行を一致させることはできますが、ループが終了したようです。私が間違っていること、またはより良いアプローチがあるかどうかはわかりません。どんな助けでも大歓迎です!

いくつかのメモ:

  • 行を分割すると、XYZ ID 列は行 [2] でインデックス付けされます。ここで、len(行) == 11 です。
  • ファイルをループして、各行について、ファイルの残りの行をスキャンして「一致」を見つける内部ループを作成しようとしています。
  • 一致が見つかった場合は、値を比較できるようにこれを返したい
  • 問題は、最初の一致が見つかった後にコードが壊れているように見えるため、最初に見つかった一致のみが返されることです

以下は、私のコードと、私が使用しているログ ファイルのサンプルです (一部のビジネス データを非公開にするために編集された文字列が含まれています)。実際のログファイルには、このフォーラムに貼り付ける前に削除されたカンマが含まれています。

f = open('t.log','r')
for line in f:
    aline = line.replace(',','').split()
    if len(aline)==11:
        for line in f:
            bline = line.replace(',','').split()
            if len(bline)==11 and aline[2]==bline[2]:
                print 'a: ', aline
                print 'b: ', bline

#t.log

[13:40:19.xxx009] status    -------             
[13:40:19.xxx013] status    XYZ -4  -5675.36     quote  449.70/- 449.78 avg 1418.84 -7474.48       0.134     -55.630    -395.148    
[13:40:19.xxx021] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16
[13:40:19.xxx024] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70
[13:40:19.xxx027] status    XYZ  ID:22P0099xxx0 10  -17.18   quote:    1.86/   1.90  avg:   -1.72    1.42
[13:40:19.xxx029] status    XYZ  ID:22C00995xxx 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70
[13:40:19.xxx031] status    XYZ  ID:22P00995xxx 2   9.66     quote:    3.30/   3.40  avg:    4.83   16.26
[13:40:19.xxx535] status    total xx5.52                

[13:41:20.xxx688] status    -------             
[13:41:20.xxx691] status    XYZ -4  -5675.36     quote  449.83/- 449.99 avg 1418.84 -7475.32      -0.374    -213.006     -39.391    
[13:41:20.xxx701] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.96/   1.00  avg:   -0.98   -0.08
[13:41:20.xxx704] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.65/  11.90  avg:  -13.20    2.60
[13:41:20.xxx708] status    XYZ  ID:22P0099xxx0 10  -17.18   quote:    1.83/   1.87  avg:   -1.72    1.12
[13:41:20.xxx712] status    XYZ  ID:22C00995xxx 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70
[13:41:20.xxx716] status    XYZ  ID:22P00995xxx 2   9.66     quote:    3.30/   3.35  avg:    4.83   16.26
[13:41:20.xxx718] status    XYZ  ID:22C0095xxx0 -10 35.6     quote:    5.40/   5.50  avg:   -3.56  -19.40
[13:41:20.001362] status    total xx6.68    

Result:    
$ python pnlcomp.py
    a:  ['[13:40:19.000021]', 'statusAAPL', '130322P00435000', '-4', '3.92', 'quote:', '0.98/', '1.02', 'avg:', '-0.98', '-0.16']
    b:  ['[13:41:20.000701]', 'statusAAPL', '130322P00435000', '-4', '3.92', 'quote:', '0.96/', '1.00', 'avg:', '-0.98', '-0.08']
4

3 に答える 3

1

そのためには、おそらく正規表現(regexとも呼ばれます)を使用する必要があります。Pythonには、Pythonの正規表現を実装するreモジュールがあります。

見る方向の例としてこれを参照してください:文字列内の複数の一致を見つけるstackoverflowの質問

上記からの抜粋:ログファイルは次のようになります。

[1242248375] SERVICE ALERT: myhostname.com;DNS: Recursive;CRITICAL

正規表現は次のようになります。

regexp = re.compile(r'\[(\d+)\] SERVICE NOTIFICATION: (.+)')

これは次のようになります:

  • r =>生の文字列(正規表現では常に推奨)
  • \ [=>角括弧に一致します(それ以外の場合は特殊文字になります)
  • (\ d +)=>1つ以上の小数に一致\d =小数、1つ以上の場合は+
  • \]=>閉じ角括弧が続きます
  • サービス通知:=>これらの文字を順番に正確に一致させます。
  • (。+)=>。(ドット)は任意の文字に一致します。また、+は1以上を意味します

Paranthesesは結果をグループ化します。

ログファイル形式から始めるために短い正規表現を作成しました。上からのログがlog.txtとして保存されていると仮定します。

import re
regexp = re.compile(r'\[(\d{2}:\d{2}:\d{2}\.xxx\d{3})\][\s]+status[\s]+XYZ[\s]+ID:([0-9A-Zx]+)(.+)')

f = open("log.txt", "r")
for line in f.readlines():
    print line
    m = re.match(regexp, line)
    #print m
    if m:
        print m.groups()

正規表現は一見簡単ではなく、わかりやすいものではありませんが、正規表現またはre AND pythonを検索すると、役立つ例が見つかります。

私のためにこれを打ち負かす:

[13:40:19.xxx021] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16

('13:40:19.xxx021', '22P00935xxx', ' -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16')
[13:40:19.xxx024] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70

('13:40:19.xxx024', '22C0099xxx0', ' -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70')
[13:40:19.xxx027] status    XYZ  ID:22P0099xxx0 10  -17.18   quote:    1.86/   1.90  avg:   -1.72    1.42

('13:40:19.xxx027', '22P0099xxx0', ' 10  -17.18   quote:    1.86/   1.90  avg:   -1.72    1.42')
[13:40:19.xxx029] status    XYZ  ID:22C00995xxx 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70

('13:40:19.xxx029', '22C00995xxx', ' 4   -42.5    quote:    8.20/   8.30  avg:  -10.62   -9.70')
[13:40:19.xxx031] status    XYZ  ID:22P00995xxx 2   9.66     quote:    3.30/   3.40  avg:    4.83   16.26
('13:40:19.xxx031', '22P00995xxx', ' 2   9.66     quote:    3.30/   3.40  avg:    4.83   16.26')

1行おきに、一致したグループを含むリストである出力があります。

上記のプログラムにこれを追加する場合:

print "ID is : ", m.groups()[1]

出力は次のとおりです。

[13:40:19.xxx021] status    XYZ  ID:22P00935xxx -4  3.92     quote:    0.98/   1.02  avg:   -0.98   -0.16

ID is :  22P00935xxx

[13:40:19.xxx024] status    XYZ  ID:22C0099xxx0 -2  26.4     quote:   11.60/  11.85  avg:  -13.20    2.70

ID is :  22C0099xxx0

比較したいIDと一致します。少し遊んで、本当に欲しい結果を得ることができます。

最後の例 では、IDをキャッチし、IDがすでに存在するかどうかをテストして、一致した行を、キーとしてteIDを持つ辞書に追加します。

import re regexp = re.compile(r'[(\ d {2}:\ d {2}:\ d {2} .xxx \ d {3})] [\ s] + status [\ s] + XYZ [\ s] + ID:([0-9A-Zx] +)(。+)')

res = {}

f = open("log.txt", "r")
for line in f.readlines():
    print line
    m = re.match(regexp, line)  
    if m:
        print m.groups()
        id = m.groups()[1]
        if id in res:
            #print "added to existing ID"
            res[id].append([m.groups()[0], m.groups()[2]])
        else:
            #print "new ID"
            res[id] = [m.groups()[0], m.groups()[2]]

for id in res:
    print "ID: ", id
    print res[id]

これで、遊んで微調整して、ニーズに合わせることができます。

于 2013-03-19T21:35:41.567 に答える
1

フィルター機能を使用して、「ID」を含む行を取得できます。

file = open('t.log', 'r')
result = filter(lambda s: "ID" in s, file)

リスト内包表記を使用することもできます。

file = open('t.log', 'r')
result = [s for s in file if 'ID' in s]
于 2013-03-19T21:22:29.037 に答える
0

これはおそらく問題を解決するための最良の方法ではありませんが、それを機能させる方法を知りたい場合は、次のようにします。

ここでの問題は、内側のfor line in f:ループがファイルの残り全体を消費することです。したがって、外側のループに戻ると、読み取るものが何も残っていません。(2つ目の問題があります。データに対してコードを実行すると、len(aline)常に11ではなく12になります。しかし、これは簡単な修正です。)

これはファイルに固有のものではありません。これが、Pythonですべてのイテレータが機能する方法です。イテレータでこれを処理する一般的な方法は2つあり、さらに1つのファイル固有のソリューションがあります。

まず、がありitertools.teeます。これはイテレータを取り、それぞれが独立して進めることができる2つのイテレータを返します。裏で、同期が外れた場合に処理するためにストレージを使用する必要があることは明らかです。そのため、ドキュメントには次のように記載されています。

一般に、あるイテレータが別のイテレータが開始する前にほとんどまたはすべてのデータを使用する場合は、tee()の代わりにlist()を使用する方が高速です。

そして、それはもう1つのオプションです。イテレータ全体をに読み込んでlist、スライスをループできるようにします。

これは明らかに、一方のイテレータがほとんどのデータを使用し、もう一方のイテレータが待機している場合の1つです。たとえば、最初に内側のループを通過するときは、外側のループが1行目を読み取る前に、1〜20000行を読み取っています。したがって、listここではaの方が適しています。それで:

f = open('t.log','r')
contents = list(f)
f.close()
for idx, line in enumerate(contents):
    aline = line.replace(',','').split()
    if len(aline)==11:
        for line in contents[idx+1:]:
            bline = line.replace(',','').split()
            if len(bline)==11 and aline[2]==bline[2]:
                print 'a: ', aline
                print 'b: ', bline

最後に、何らかの方法でチェックポイントを設定して再開できるファンシーなイテレータがある場合は、内側のループの直前にチェックポイントを設定し、直後に再開できます。そして幸いなことに、ファイルにはそのようなものtellがあります。現在のファイル位置を返し、seek指定された位置にジャンプします。(「ファイルがテキストモード(なし'b')で開かれている場合、によって返されるオフセットのみtell()が有効です」という大きな警告があります。しかし、それは問題ありませんtell。ここで返されるオフセットのみを使用しています。)

それで:

f = open('t.log','r')
for line in f:
    aline = line.replace(',','').split()
    if len(aline)==11:
        pos = f.tell()
        for line in f:
            bline = line.replace(',','').split()
            if len(bline)==11 and aline[2]==bline[2]:
                print 'a: ', aline
                print 'b: ', bline
        f.seek(pos)
于 2013-03-19T21:37:03.407 に答える