2010-05-09 12 views
6

que tiene una cadena como la siguiente:cadena Pyparsing CSV con citas aleatorias

<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="[email protected]",mailer="mta",client_name="example.org,[194.177.17.24]",resolved=OK,to="[email protected]",direction="in",message_length=6832079,virus="",disposition="Accept",classifier="Not,Spam",subject="=?windows-1255?B?Rlc6IEZ3OiDg5fDp5fog+fno5fog7Pf46eHp7S3u4+Tp7SE=?=" 

He intentado utilizar el módulo CSV y que no encajaba, porque yo no he encontrado una manera de ignorar lo que está citado. Pyparsing parecía una mejor respuesta, pero no he encontrado una forma de declarar todas las gramáticas.

Actualmente, estoy usando mi antiguo script de Perl para analizarlo, pero quiero que esté escrito en Python. si necesita mi fragmento de Perl, estaré encantado de proporcionarlo.

Cualquier ayuda es apreciada.

Respuesta

5

No estoy seguro de lo que realmente está buscando, pero

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=\"[email protected]\",mailer=\"mta\",client_name=\"example.org,[194.177.17.24]\",resolved=OK,to=\"[email protected]\",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)) 

le da

[('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', '"[email protected]"'), ('mailer', '"mta"'), 
('client_name', '"example.org,[194.177.17.24]"'), ('resolved', 'OK'), 
('to', '"[email protected]"'), ('direction', '"in"'), 
('message_length', '6832079'), ('virus', '""'), ('disposition', '"Accept"'), 
('classifier', '"Not,Spam"'), 
('subject', '"=?windows-1255?B?Rlc6IEZ3OiDg5fDp5fog+fno5fog7Pf46eHp7S3u4+Tp7SE=?="') 
] 

Es posible que desee para limpiar las cadenas entre comillas después (usando mystring.strip("'\"")).

EDIT: Esta expresión regular ahora también maneja correctamente las comillas escapadas dentro de las cadenas entre comillas (a="She said \"Hi!\"").

Explicación de la expresión regular:

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

(\w+): coincidir con el identificador y la captura en referencia inversa no. 1

=: coincidir con un =

(: capturar el siguiente en referencia inversa no. 2:

(?:: Uno de los siguientes:

"(?:\\.|[^\\"])*": Una doble cita, seguido de cero o más de los siguientes: un carácter de escape o un carácter/no backslash no cita, seguido de otro comillas dobles

|: o

'(?:\\.|[^\\'])*': Véase más arriba, sólo por comillas simples.

|: o

[^\\,"']: un carácter que no es ni una barra invertida, una coma, ni una cita.

)+: repetir al menos una vez, tantas veces como sea posible.

): fin del grupo de captura no. 2.

+0

Gracias este hizo lo que necesitaba. – gtfx

+0

¡¡Así es como lo haces con la expresión regular !! :) – jathanism

6

Podría ser mejor aprovechar un analizador existente que utilizar expresiones regulares ad-hoc.

parse_http_list(s) 
    Parse lists as described by RFC 2068 Section 2. 

    In particular, parse comma-separated lists where the elements of 
    the list may include quoted-strings. A quoted-string could 
    contain a comma. A non-quoted string could have quotes in the 
    middle. Neither commas nor quotes count if they are escaped. 
    Only double-quotes count, not single-quotes. 

parse_keqv_list(l) 
    Parse list of key=value strings where keys are not duplicated. 

Ejemplo:

>>> 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': '[email protected]', 
'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': '[email protected]', 
'type': 'statistics', 
'virus': ''} 
+0

Créditos van a @Piotr Czapla http://stackoverflow.com/questions/1349367/parse-an-http-request-authorization-header-with-python/1349626#1349626 – jfs

+0

Ok wow, esto es realmente una joya de una solución. Gracias. – jathanism

+0

Excelente, especialmente porque ya elimina las cotizaciones innecesarias. Bueno, esa es la belleza de Python para ti: baterías incluidas. (Aunque mi expresión regular tampoco es tan mala :)) –