8

次の複数行のデータファイルをPythonで解析するための最良の方法は何ですか?

Police Response: 11/6/2012 1:34:06 AM   Incident Desc: Traffic Stop OFC:    Received: 11/6/2012 1:34:06 AM
Disp: PCHK  Location: CLEAR LAKE RD&GREEN HILL RD
Event Number: LLS121106060941   ID: 60941   Priority: 6 Case No:
Police Response:    Incident Desc: Theft    OFC:    Received: 11/6/2012 1:43:35 AM
Disp: CSR   Location: SCH BLACHLY
Event Number: LLS121106060943   ID: 60943   Priority: 4 Case No:
Police Response: 11/6/2012 1:47:47 AM   Incident Desc: Suspicious Vehicle(s)    OFC:        Received: 11/6/2012 1:47:47 AM
Disp: FI    Location: KIRK RD&CLEAR LAKE RD
Event Number: LLS121106060944   ID: 60944   Priority: 6 Case No:

レコードは常に3行に分割されます。「PoliceResponse」で始まり「EventNumber」で終わる行です。一部のフィールドは空白であることがよくあります。

4

4 に答える 4

10

これでうまくいくはずです。あなたが持っているデータを、それぞれがあなたのデータの行を含むケースのリストに分割します。次に、正規表現スパイティングを使用して、フィールド名で分割しました。その後、キーと値のペアのリストをディクショナリに入れ、ケースを簡単にループして、ディクショナリを使用して任意のフィールド値にアクセスできるようにします。データ構造を示すためだけに、行の内容を出力します。

コード

from pprint import pprint
from collections import OrderedDict
import re

data = """Police Response: 11/6/2012 1:34:06 AM   Incident Desc: Traffic Stop OFC:    Received: 11/6/2012 1:34:06 AM
Disp: PCHK  Location: CLEAR LAKE RD&GREEN HILL RD
Event Number: LLS121106060941   ID: 60941   Priority: 6 Case No:
Police Response:    Incident Desc: Theft    OFC:    Received: 11/6/2012 1:43:35 AM
Disp: CSR   Location: SCH BLACHLY
Event Number: LLS121106060943   ID: 60943   Priority: 4 Case No:
Police Response: 11/6/2012 1:47:47 AM   Incident Desc: Suspicious Vehicle(s)    OFC:        Received: 11/6/2012 1:47:47 AM
Disp: FI    Location: KIRK RD&CLEAR LAKE RD
Event Number: LLS121106060944   ID: 60944   Priority: 6 Case No: """

lines = data.splitlines()
cases = ['\n'.join(lines[i:i+3]) for i in range(0, len(lines), 3)]
pattern = '(Police Response|Incident Desc|OFC|Received|Disp|Location|Event Number|ID|Priority|Case No):'
rows = []
for case in cases:
    pairs =  re.split(pattern, case)[1:]
    rows.append(OrderedDict((pairs[i*2], pairs[i*2+1]) for i in range(10)))

for i, row in enumerate(rows):
    print '============== {} =============='.format(i)
    pprint(row.items())

出力:

============== 0 ==============
[('Police Response', ' 11/6/2012 1:34:06 AM   '),
 ('Incident Desc', ' Traffic Stop '),
 ('OFC', '    '),
 ('Received', ' 11/6/2012 1:34:06 AM\n'),
 ('Disp', ' PCHK  '),
 ('Location', ' CLEAR LAKE RD&GREEN HILL RD\n'),
 ('Event Number', ' LLS121106060941   '),
 ('ID', ' 60941   '),
 ('Priority', ' 6 '),
 ('Case No', '')]
============== 1 ==============
[('Police Response', '    '),
 ('Incident Desc', ' Theft    '),
 ('OFC', '    '),
 ('Received', ' 11/6/2012 1:43:35 AM\n'),
 ('Disp', ' CSR   '),
 ('Location', ' SCH BLACHLY\n'),
 ('Event Number', ' LLS121106060943   '),
 ('ID', ' 60943   '),
 ('Priority', ' 4 '),
 ('Case No', '')]
============== 2 ==============
[('Police Response', ' 11/6/2012 1:47:47 AM   '),
 ('Incident Desc', ' Suspicious Vehicle(s)    '),
 ('OFC', '        '),
 ('Received', ' 11/6/2012 1:47:47 AM\n'),
 ('Disp', ' FI    '),
 ('Location', ' KIRK RD&CLEAR LAKE RD\n'),
 ('Event Number', ' LLS121106060944   '),
 ('ID', ' 60944   '),
 ('Priority', ' 6 '),
 ('Case No', ' ')]
于 2012-11-08T18:43:06.040 に答える
3

大きな疑問:

エントリを区切るために使用されるものは何ですか? エントリ間にタブがある場合は、各行をタブで分割するだけで簡単になります。常に少なくとも 2 つのスペースがある場合は、それで分割できます。スペースが 1 つしかない場合があると、事態が複雑になります。

それ以外の場合は、一度に 3 行を吐き出すジェネレーター/関数を作成して、3 行を解析する関数にスローするのは簡単です。問題の「一度に 3 行」の部分は簡単な部分です。

def return_3(file):
    return [file.next() for i in range(3)]
于 2012-11-08T18:28:07.250 に答える
0

入力データ形式に一貫性があると仮定すると、次のようにアプローチできます。

# List of fields. Corresponds to colums and rows in input data.
fields = (
  ("Police Response", "Incident Desc", "OFC", "Received"),
  ("Disp", "Location"),                                    
  ("Event Number", "ID", "Priority", "Case No")
)

# generate pattern based on fields
patterns = [re.compile(":(.*)".join(f) + ":(.*)") for f in fields]

ここでは、フィールドのリストに基づいて検索パターンを生成します。これにより、予想されるデータ形式を簡単に表示および更新できます。

生成されたパターンを使用して、対応する文字列のリストを、フィールド名をキーとして持つdictに解析できます。

def parse_record(lines):
  out = {}
  for f, p, s in zip(fields, patterns, lines):
     out.update(zip(f, [s.strip() for s in p.match(s).groups()]))
  return out

簡潔にするために、エラーチェックは省略しましたが、いくつかのチェックを追加すると、入力データが期待どおりでない場合に、よりわかりやすいエラーメッセージを出力できるようになります。特に、それを表明し、を返すlen(lines) == len(fields)ときに発生する例外をキャッチします。p.match(s)None

最後の部分は、各レコードの数または行で入力データをグループ化することです。grouper()これは、レシピを使用して非常に簡単に行うことができます。

次に例を示します。

for lines in grouper(len(fields), open("input_data.txt"):
  record = parse_record(lines)
  print record["ID"], record["Incident Desc"]  # do something with the dict
于 2012-11-09T10:06:52.193 に答える
0

この正規表現は機能するはずです:

data = open('file.dat').read()

re.findall("""Police Response:(.*)Incident Desc:(.*)OFC:(.*)Received:(.*)
Disp:(.*)Location:(.*)
Event Number:(.*)Priority:(.*)Case No:(.*)""", data)
于 2012-11-08T19:07:07.077 に答える