2016-06-07 10 views
3

Ich habe die folgende Zeichenfolge in eine Reportdatei:lesen Bunch() von String

"Bunch(conditions=['s1', 's2', 's3', 's4', 's5', 's6'], durations=[[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]], onsets=[[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]])" 

Ich mag würde es in ein Bunch() Objekt oder ein dict drehen, so dass ich die Informationen innerhalb zugreifen können (über entweder my_var.conditions oder my_var["conditions"]).

Das funktioniert sehr gut mit eval():

eval("Bunch(conditions=['s1', 's2', 's3', 's4', 's5', 's6'], durations=[[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]], onsets=[[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]])") 

aber ich würde, dass die Verwendung vermeiden möchten.

Ich habe versucht, ein paar String-Substitutionen zu schreiben, so dass ich es in eine dict-Syntax umwandeln und dann mit json.loads() analysieren, aber das sieht sehr sehr hackish aus, und wird brechen, sobald ich irgendwelche neuen Felder in zukünftigen Strings ; Beispiel:

"{"+"Bunch(conditions=['s1', 's2', 's3', 's4', 's5', 's6'], durations=[[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]], onsets=[[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]])"[1:-1]+"}".replace("conditions=","'conditions':") 

Sie erhalten die Idee.

Wissen Sie, ob es eine bessere Möglichkeit gibt, das zu parsen?

+0

Was genau ist Ihre endgültige erwartete Ausgabe? Kannst du auch zeigen, was du bisher getan hast, um eine Vorstellung davon zu bekommen, wie dein Ansatz ist? – idjaw

Antwort

2

Dieser pyparssing-Code definiert einen analysierenden Ausdruck für Ihre Bündeldeklaration.

from pyparsing import (pyparsing_common, Suppress, Keyword, Forward, quotedString, 
    Group, delimitedList, Dict, removeQuotes, ParseResults) 

# define pyparsing parser for the Bunch declaration 
LBRACK,RBRACK,LPAR,RPAR,EQ = map(Suppress, "[]()=") 
integer = pyparsing_common.integer 
real = pyparsing_common.real 
ident = pyparsing_common.identifier 

# define a recursive expression for nested lists 
listExpr = Forward() 
listItem = real | integer | quotedString.setParseAction(removeQuotes) | Group(listExpr) 
listExpr << LBRACK + delimitedList(listItem) + RBRACK 

# define an expression for the Bunch declaration 
BUNCH = Keyword("Bunch") 
arg_defn = Group(ident + EQ + listItem) 
bunch_decl = BUNCH + LPAR + Dict(delimitedList(arg_defn))("args") + RPAR 

ist hier, dass Parser gegen Ihre Abtastwerteingang laufen:

# run the sample input as a test 
sample = """Bunch(conditions=['s1', 's2', 's3', 's4', 's5', 's6'], 
        durations=[[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]], 
        onsets=[[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]])""" 
bb = bunch_decl.parseString(sample) 
# print the parsed output as-is 
print(bb) 

Gibt:

['Bunch', [['conditions', ['s1', 's2', 's3', 's4', 's5', 's6']], 
    ['durations', [[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]]], 
    ['onsets', [[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]]]]] 

Mit pyparsing, können Sie auch einen Parse-Zeit Rückruf hinzufügen, so dass pyparsing wird Machen Sie die Token-> Bunch Umwandlung für Sie:

# define a simple placeholder class for Bunch 
class Bunch(object): 
    def __init__(self, **kwargs): 
     self.__dict__.update(kwargs) 
    def __repr__(self): 
     return "Bunch:(%s)" % ', '.join("%r: %s" % item for item in vars(self).items()) 

# add this as a parse action, and pyparsing will autoconvert the parsed data to a Bunch 
bunch_decl.addParseAction(lambda t: Bunch(**t.args.asDict())) 

Jetzt wird der Parser Ihnen eine tatsächliche Bunch-Instanz geben:

[Bunch:('durations': [[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]], 
     'conditions': ['s1', 's2', 's3', 's4', 's5', 's6'], 
     'onsets': [[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]])] 
+0

Noice! Ausgezeichnetes Timing! Ich hatte gerade angefangen, über eine kleine Grammatik in Lex/Yacc nachzudenken (Old Dogs usw.), obwohl ich wirklich in Python bleiben wollte. Ich hatte das Pyapsen völlig vergessen. –

+0

Wenn Sie wirklich lex/yacc gehen wollen, können Sie mit PLY immer noch in Python bleiben. – PaulMcG

2

Hier mein hässliches Stück Code ist, überprüfen Sie bitte:

import re 
import json 
l = "Bunch(conditions=['s1', 's2', 's3', 's4', 's5', 's6'], durations=[[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]], onsets=[[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]])" 

exec('{}="{}"'.format(l[:5],l[6:-1])) 
sb = re.split("=| [a-zA-Z]", Bunch) 
temp = ['"{}"'.format(x) if x.isalpha() else x for x in sb ] 
temp2 = ','.join(temp) 
temp3 = temp2.replace('",[', '":[') 
temp4 = temp3.replace(',,', ',') 
temp5 = temp4.replace("\'", '"') 
temp6 = """{%s}""" %(temp5) 
rslt = json.loads(temp6) 

Schließlich ist der Ausgang:

rslt 
Out[12]: 
{'urations': [[30.0], [30.0], [30.0], [30.0], [30.0], [30.0]], 
'conditions': ['s1', 's2', 's3', 's4', 's5', 's6'], 
'nsets': [[172.77], [322.77], [472.77], [622.77], [772.77], [922.77]]} 

rslt["conditions"] 
Out[13]: ['s1', 's2', 's3', 's4', 's5', 's6'] 

Im Allgemeinen denke ich re ist das Paket, das Sie benötigen, aber aufgrund meiner begrenzten Erfahrung damit, ich könnte es hier gut anwenden. Hoffe, jemand anderes wird eine elegantere Lösung geben.

FYI, Sie sagten, Sie könnten einfach eval verwenden, um zu bekommen, was Sie wollen, aber wenn ich versuche, es zu verwenden, habe ich TypeError: 'str' object is not callable. Welche Python-Version verwendest du? (Ich habe es auf Python27 und Python33 versucht, beide können nicht funktionieren)

Verwandte Themen