2012-07-04 18 views
6

Por razones que realmente no entiendo, una API REST que estoy usando, en lugar de generar JSON o XML, usa un formato de texto estructurado peculiar. En su forma más simpleAnalizando un archivo de texto estructurado en Python (pyparsing)

SECTION_NAME entry other qualifying bits of the entry 
       entry2 other qualifying bits 
       ... 

No son delimitado por tabuladores, ya que la estructura pueda parecer, pero en vez delimitados en el espacio, y los bits de calificación pueden contener palabras con espacios. El espacio entre SECTION_NAME y las entradas también es variable, que va de 1 a varios (6 o más) espacios.

Además, una parte del formato contiene entradas en forma

SECTION_NAME entry 
    SUB_SECTION more information 
    SUB_SECTION2 more information 

Para referencia, un extracto de datos reales (algunas secciones omitidas), que muestra el uso de la estructura:

ENTRY  hsa04064     Pathway 
NAME  NF-kappa B signaling pathway - Homo sapiens (human) 
DRUG  D09347 Fostamatinib (USAN) 
      D09348 Fostamatinib disodium (USAN) 
      D09692 Veliparib (USAN/INN) 
      D09730 Olaparib (JAN/INN) 
      D09913 Iniparib (USAN/INN) 
REFERENCE PMID:21772278 
    AUTHORS Oeckinghaus A, Hayden MS, Ghosh S 
    TITLE  Crosstalk in NF-kappaB signaling pathways. 
    JOURNAL Nat Immunol 12:695-708 (2011) 

Como estoy tratando de convertir este extraño formato en algo más sensato (un diccionario que luego puede convertirse en JSON), no estoy seguro de qué hacer: dividir ciegamente en espacios causa un desastre (también afecta la información con espacios)), y no estoy seguro de cómo puedo saber cuándo comienza una sección o n Antiguo Testamento. ¿La manipulación de texto es suficiente para el trabajo o debería usar métodos más sofisticados?

EDIT:

que comenzó a usar pyparsing para el trabajo, pero de múltiples línea de registros me desconciertan, he aquí un ejemplo con la droga:

from pyparsing import * 
punctuation = ",.'`&-" 
special_chars = "\()[]" 

drug = Keyword("DRUG") 
drug_content = Word(alphanums) + originalTextFor(OneOrMore(Word(
     alphanums + special_chars))) + ZeroOrMore(LineEnd()) 
drug_lines = OneOrMore(drug_content) 
drug_parser = drug + drug_lines 

Cuando se aplica a las 3 primeras líneas de fármaco en el ejemplo, aparece un resultado erróneo (\ n convertido a los rendimientos reales para facilitar la legibilidad):

['DRUG', ['D09347', 'Fostamatinib (USAN) 
     D09348 Fostamatinib disodium  (USAN) 
     D09692 Veliparib (USAN']] 

Como se puede ver, las entradas subsiguientes quedan agrupados todos juntos, mientras yo esperaría:

['DRUG', [['D09347', 'Fostamatinib (USAN)'], ["D09348", "Fostamatinib disodium (USAN)"], 
      ['D09692', ' Veliparib (USAN)']]] 
+0

Ha intentado dividir el espacio en blanco, pero limitando el número de divisiones? – inspectorG4dget

+0

@ inspectorG4dget: lo pensé, pero las entradas individuales tienen requisitos de espacio variable (por lo que probablemente cada sección requeriría su número específico de divisiones) – Einar

+0

¡Ajá! Entonces quizás ['re.split'] (http://docs.python.org/library/re.html#re.split) sea una mejor opción – inspectorG4dget

Respuesta

3

Recomiendo que utilice un enfoque basado en analizador. Por ejemplo, Python PLY se puede utilizar para la tarea en cuestión.

+0

Voy a probar esto y las soluciones de Antonio Beamud en breve. Gracias. – Einar

+2

@Einar Otra opción de análisis sería http://pyparsing.wikispaces.com/, que tiene documentación razonable y un montón de ejemplos. –

+0

Se ha agregado una prueba con pyparsing, llegando allí para una línea, pero sigue teniendo problemas con varias líneas. – Einar

0

El mejor enfoque es el uso de expresiones regulares, como:

m = re.compile('^ENTRY\s+(.*)$') 
m.search(line) 
if m: 
    m.groups()[0].strip() 

de líneas sin entrada, se debe utilizar la última entrada que detecta.

Un enfoque más sencillo es dividir por la entrada, por ejemplo:

vals = line.split('DRUG') 
if len(vals) > 1: 
    drug_field = vals[1].strip() 
Cuestiones relacionadas