2012-07-04 14 views
6

Per ragioni che non comprendo, un'API REST che sto usando, invece di emettere JSON o XML, usa un formato di testo strutturato peculiare. Nella sua forma più sempliceAnalizzare un file di testo strutturato in Python (pyparsing)

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

Non sono tabulazioni, come la struttura può sembrare, ma invece delimitato da spazi, ei bit di qualificazione possono contenere parole con spazi. Lo spazio tra SECTION_NAME e le voci è anche variabile, che va da 1 a diversi (6 o più) spazi.

Inoltre, una parte del formato contiene voci nella forma

SECTION_NAME entry 
    SUB_SECTION more information 
    SUB_SECTION2 more information 

Per riferimento, un estratto di dati reali (alcune sezioni omessi), che mostra l'uso della struttura:

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) 

Mentre sto cercando di analizzare questo strano formato in qualcosa di più sano (un dizionario che può essere convertito in JSON), non sono sicuro su cosa fare: spaccare ciecamente sugli spazi causa un pasticcio (influenza anche le informazioni con gli spazi), e non sono sicuro su come posso capire quando una sezione inizia o n ot. La manipolazione del testo è sufficiente per il lavoro o dovrei usare metodi più sofisticati?

EDIT:

ho iniziato ad usare pyparsing per il lavoro, ma più righe record me deflettore, ecco un esempio 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 

Quando applicata alle prime 3 righe del farmaco nel ad esempio, ho un risultato sbagliato (\ n convertito in rendimenti effettivi per facilitare la leggibilità):

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

Come si può vedere, le voci successive vengono ammassati tutti insieme, mentre mi aspetto:

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

Hai provato splitting su spazi vuoti, ma limitando il numero di divisioni? – inspectorG4dget

+0

@ inspectorG4dget: ci ho pensato, ma le singole voci hanno requisiti di spazio variabile (quindi probabilmente ogni sezione richiederebbe il suo numero specifico di divisioni) – Einar

+0

Aha! Quindi forse ['re.split'] (http://docs.python.org/library/re.html#re.split) sarebbe una scelta migliore – inspectorG4dget

risposta

3

Si consiglia di utilizzare un approccio basato su parser. Ad esempio, Python PLY può essere utilizzato per l'attività in corso.

+0

Testerò questo e le soluzioni di Antonio Beamud a breve. Grazie. – Einar

+2

@Einar Un'altra opzione di parsing sarebbe http://pyparsing.wikispaces.com/ che ha una documentazione ragionevole e un sacco di esempi –

+0

Aggiunto un tentativo con pyparsing, arrivare lì per single-line, ma ancora problemi con multi-line. – Einar

0

L'approccio migliore è quello di utilizzare le espressioni regolari, come:

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

per le linee senza immissione, è necessario utilizzare l'ultima voce che si rilevato.

Un approccio più semplice è raggruppati per l'ingresso, per esempio:

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