2012-07-04 10 views
6

Aus Gründen, die ich wirklich nicht verstehe, verwendet eine REST API, die ich anstelle von JSON oder XML verwende, ein eigenartiges strukturiertes Textformat. In seiner einfachsten FormAnalysieren einer strukturierten Textdatei in Python (pyparsing)

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

Sie sind nicht Tabula begrenzt, da die Struktur zu sein scheint, sondern durch Leerzeichen getrennte und die Qualifikation Bits Wörter mit Leerzeichen enthalten. Der Abstand zwischen SECTION_NAME und den Einträgen ist ebenfalls variabel und reicht von 1 bis zu mehreren (6 oder mehr) Leerzeichen.

Auch ein Teil des Formates enthält Einträge in Form

SECTION_NAME entry 
    SUB_SECTION more information 
    SUB_SECTION2 more information 

Zur Bezugnahme ist ein Extrakt aus realen Daten (einige Abschnitte weggelassen), was zeigt die Verwendung der Struktur:

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) 

Während ich versuche, dieses seltsame Format in etwas Seriöseres zu parsen (ein Wörterbuch, das dann in JSON konvertiert werden kann), bin ich mir nicht sicher, was ich tun soll: Das Aufspalten von Leerzeichen verursacht Unordnung (betrifft auch Informationen mit Leerzeichen)), und ich bin mir nicht sicher, wie ich herausfinden kann, wenn ein Abschnitt beginnt oder n ot. Ist Textmanipulation für den Job ausreichend oder sollte ich anspruchsvollere Methoden verwenden?

EDIT:

begann mich für den Job mit pyparsing, aber mehrzeilige Datensätze mich verblüfft, hier ist ein Beispiel mit DRUG:

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 

Bei den ersten drei Zeilen des Wirkstoffs in der Anwendung Beispiel habe ich ein falsches Ergebnis erhalten (\ n zu tatsächlichen Erträge umgewandelt Lesbarkeit zu erleichtern):

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

Wie Sie alle zusammen in einen Topf geworfen sehen können, erhalten die nachfolgenden Einträge, während ich erwarten würde:

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

Haben Sie Splitting auf Leerzeichen versucht, aber die Anzahl der Teilungen zu begrenzen? – inspectorG4dget

+0

@inspectorG4dget: Ich habe darüber nachgedacht, aber die einzelnen Einträge haben variable Platzanforderungen (also wahrscheinlich würde jeder Abschnitt seine spezifische Anzahl von Splits erfordern) – Einar

+0

Aha! Dann wäre vielleicht ['re.split'] (http://docs.python.org/library/re.html#re.split) eine bessere Wahl – inspectorG4dget

Antwort

3

Ich würde empfehlen, dass Sie einen Parser-basierten Ansatz verwenden. Zum Beispiel kann Python PLY für die vorliegende Aufgabe verwendet werden.

+0

Ich werde diese und Antonio Beamuds Lösungen in Kürze testen. Vielen Dank. – Einar

+2

@Einar Eine weitere Parsing-Option wäre http://pyparsing.wikispaces.com/, die eine vernünftige Dokumentation und viele Beispiele enthält. –

+0

Ein Versuch mit pyparsing wurde hinzugefügt, um es für Single-Line zu bekommen, aber immer noch Probleme mit Multi-Line. – Einar

0

Der beste Ansatz ist, reguläre Ausdrücke zu verwenden, wie:

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

für Linien ohne Eintrag, können Sie den letzten Eintrag verwenden, sollten Sie festgestellt.

Ein einfacher Ansatz wird durch Eintrag aufgeteilt, zum Beispiel:

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