6

次のような文字列があります。

<118>date=2010-05-09,time=16:41:27,device_id=FE-2KA3F09000049,log_id=0400147717,log_part=00,type=statistics,subtype=n/a,pri=information,session_id=o49CedRc021772,from="prvs=4745cd07e1=example@example.org",mailer="mta",client_name="example.org,[194.177.17.24]",resolved=OK,to="example@example.org",direction="in",message_length=6832079,virus="",disposition="Accept",classifier="Not,Spam",subject="=?windows-1255?B?Rlc6IEZ3OiDg5fDp5fog+fno5fog7Pf46eHp7S3u4+Tp7SE=?="

CSV モジュールを使用してみましたが、引用されているものを無視する方法が見つからなかったため、適合しませんでした。Pyparsing はより良い答えのように見えましたが、すべての文法を宣言する方法が見つかりませんでした。

現在、古い Perl スクリプトを使用して解析していますが、これを Python で記述したいと考えています。私の Perl スニペットが必要な場合は、喜んで提供します。

どんな助けでも大歓迎です。

4

2 に答える 2

6

アドホック正規表現を使用するよりも、既存のパーサーを活用する方がよい場合があります。

parse_http_list(s)
    RFC2068セクション2で説明されているようにリストを解析します。

    特に、カンマ区切りのリストを解析します。
    リストには引用符で囲まれた文字列が含まれる場合があります。引用符で囲まれた文字列は
    カンマを含みます。引用符で囲まれていない文字列には、引用符が含まれている可能性があります
    真ん中。カンマも引用符も、エスケープされている場合はカウントされません。
    一重引用符ではなく、二重引用符のみがカウントされます。

parse_keqv_list(l)
    キーが複製されていないkey=value文字列のリストを解析します。

例:

>>> pprint.pprint(urllib2.parse_keqv_list(urllib2.parse_http_list(s)))
{'<118>date': '2010-05-09',
 'classifier': 'Not,Spam',
 'client_name': 'example.org,[194.177.17.24]',
 'device_id': 'FE-2KA3F09000049',
 'direction': 'in',
 'disposition': 'Accept',
 'from': 'prvs=4745cd07e1=example@example.org',
 'log_id': '0400147717',
 'log_part': '00',
 'mailer': 'mta',
 'message_length': '6832079',
 'pri': 'information',
 'resolved': 'OK',
 'session_id': 'o49CedRc021772',
 'subject':'=?windows-1255?B?Rlc6IEZ3OiDg5fDp5fog+fno5fog7Pf46eHp7S3u4+Tp7SE=?=',
 'subtype': 'n/a',
 'time': '16:41:27',
 'to': 'example@example.org',
 'type': 'statistics',
 'virus': ''}
于 2010-05-14T06:43:08.900 に答える
5

あなたが本当に何を求めているのかわかりませんが、

import re
data = "date=2010-05-09,time=16:41:27,device_id=FE-2KA3F09000049,log_id=0400147717,log_part=00,type=statistics,subtype=n/a,pri=information,session_id=o49CedRc021772,from=\"prvs=4745cd07e1=example@example.org\",mailer=\"mta\",client_name=\"example.org,[194.177.17.24]\",resolved=OK,to=\"example@example.org\",direction=\"in\",message_length=6832079,virus=\"\",disposition=\"Accept\",classifier=\"Not,Spam\",subject=\"=?windows-1255?B?Rlc6IEZ3OiDg5fDp5fog+fno5fog7Pf46eHp7S3u4+Tp7SE=?=\""
pattern = r"""(\w+)=((?:"(?:\\.|[^\\"])*"|'(?:\\.|[^\\'])*'|[^\\,"'])+)"""
print(re.findall(pattern, data))

あなたにあげる

[('date', '2010-05-09'), ('time', '16:41:27'), ('device_id', 'FE-2KA3F09000049'),
 ('log_id', '0400147717'), ('log_part', '00'), ('type', 'statistics'),
 ('subtype', 'n/a'), ('pri', 'information'), ('session_id', 'o49CedRc021772'),
 ('from', '"prvs=4745cd07e1=example@example.org"'), ('mailer', '"mta"'),
 ('client_name', '"example.org,[194.177.17.24]"'), ('resolved', 'OK'),
 ('to', '"example@example.org"'), ('direction', '"in"'),
 ('message_length', '6832079'), ('virus', '""'), ('disposition', '"Accept"'),
 ('classifier', '"Not,Spam"'), 
 ('subject', '"=?windows-1255?B?Rlc6IEZ3OiDg5fDp5fog+fno5fog7Pf46eHp7S3u4+Tp7SE=?="')
]

後で引用符で囲まれた文字列をクリーンアップすることをお勧めします ( を使用mystring.strip("'\""))。

編集: この正規表現は、引用符で囲まれた文字列 ( ) 内のエスケープされた引用符も正しく処理するようになりましたa="She said \"Hi!\""

正規表現の説明:

(\w+)=((?:"(?:\\.|[^\\"])*"|'(?:\\.|[^\\'])*'|[^\\,"'])+)

(\w+): 識別子を一致させ、後方参照番号にキャプチャします。1

=: 抹茶=

(: 以下を後方参照番号にキャプチャします。2:

(?:: 次のいずれか:

"(?:\\.|[^\\"])*": 二重引用符の後に次の 0 個以上が続きます: エスケープ文字または非引用符/非バックスラッシュ文字、その後に別の二重引用符

|: また

'(?:\\.|[^\\'])*': 単一引用符については、上記を参照してください。

|: また

[^\\,"']: バックスラッシュ、カンマ、引用符のいずれでもない 1 文字。

)+: 少なくとも 1 回、可能な限り何度でも繰り返します。

):撮影グループ番号終了 2.

于 2010-05-09T13:55:12.170 に答える