2010-05-31 21 views
6

Ho stringhe in questo modo:PyParsing: questo uso corretto di setParseAction()?

"MSE 2110, 3030, 4102" 

Vorrei uscita:

[("MSE", 2110), ("MSE", 3030), ("MSE", 4102)] 

Questo è il mio modo di andare su di esso, anche se non ho ancora del tutto ottenuto è:

def makeCourseList(str, location, tokens): 
    print "before: %s" % tokens 

    for index, course_number in enumerate(tokens[1:]): 
     tokens[index + 1] = (tokens[0][0], course_number) 

    print "after: %s" % tokens 

course = Group(DEPT_CODE + COURSE_NUMBER) # .setResultsName("Course") 

course_data = (course + ZeroOrMore(Suppress(',') + COURSE_NUMBER)).setParseAction(makeCourseList) 

This uscite:

>>> course.parseString("CS 2110") 
([(['CS', 2110], {})], {}) 
>>> course_data.parseString("CS 2110, 4301, 2123, 1110") 
before: [['CS', 2110], 4301, 2123, 1110] 
after: [['CS', 2110], ('CS', 4301), ('CS', 2123), ('CS', 1110)] 
([(['CS', 2110], {}), ('CS', 4301), ('CS', 2123), ('CS', 1110)], {}) 

È questo il modo giusto per farlo, o sono totalmente fuori servizio?

Inoltre, l'output di non è del tutto corretto - Voglio course_data per emettere un elenco di simboli course che si trovano nello stesso formato l'uno dell'altro. In questo momento, il primo corso è diverso dagli altri. (Ha un {}, mentre gli altri non lo fanno.)

+4

Dovresti accettare una risposta, penso. – Donovan

risposta

5

È questo il modo giusto per farlo, o sono Sono assolutamente fuori?

È un modo per farlo, anche se naturalmente ci sono altri (ad esempio l'uso come azioni parse due metodo vincolato - così l'istanza del metodo appartiene può mantenere lo stato - uno per il codice reparto e un'altra per il numero del corso).

Il valore restituito della chiamata parseString è più difficile da piegare al proprio testamento (anche se sono sicuro che la magia sufficientemente oscura lo farà e non vedo l'ora che Paul McGuire spieghi come ;-), quindi perché non andare al limite metodo percorso come in ...:

from pyparsing import * 

DEPT_CODE = Regex(r'[A-Z]{2,}').setResultsName("DeptCode") 
COURSE_NUMBER = Regex(r'[0-9]{4}').setResultsName("CourseNumber") 

class MyParse(object): 
    def __init__(self): 
     self.result = None 

    def makeCourseList(self, str, location, tokens): 
     print "before: %s" % tokens 

     dept = tokens[0][0] 
     newtokens = [(dept, tokens[0][1])] 
     newtokens.extend((dept, tok) for tok in tokens[1:]) 

     print "after: %s" % newtokens 
     self.result = newtokens 

course = Group(DEPT_CODE + COURSE_NUMBER).setResultsName("Course") 

inst = MyParse() 
course_data = (course + ZeroOrMore(Suppress(',') + COURSE_NUMBER) 
    ).setParseAction(inst.makeCourseList) 
ignore = course_data.parseString("CS 2110, 4301, 2123, 1110") 
print inst.result 

questo emette:

before: [['CS', '2110'], '4301', '2123', '1110'] 
after: [('CS', '2110'), ('CS', '4301'), ('CS', '2123'), ('CS', '1110')] 
[('CS', '2110'), ('CS', '4301'), ('CS', '2123'), ('CS', '1110')] 

che sembra essere ciò che si richiede, se ho letto bene le caratteristiche del tuo.

16

Questa soluzione memorizza il reparto quando viene analizzato ed emette una tupla (dept, coursenum) quando viene trovato un numero.

from pyparsing import Suppress,Word,ZeroOrMore,alphas,nums,delimitedList 

data = '''\ 
MSE 2110, 3030, 4102 
CSE 1000, 2000, 3000 
''' 

def memorize(t): 
    memorize.dept = t[0] 

def token(t): 
    return (memorize.dept,int(t[0])) 

course = Suppress(Word(alphas).setParseAction(memorize)) 
number = Word(nums).setParseAction(token) 
line = course + delimitedList(number) 
lines = ZeroOrMore(line) 

print lines.parseString(data) 

uscita:

[('MSE', 2110), ('MSE', 3030), ('MSE', 4102), ('CSE', 1000), ('CSE', 2000), ('CSE', 3000)] 
0

Certo, everbody ama PyParsing. Per le cose facili come questo split è sooo molto più facile Grok:

data = '''\ 
MSE 2110, 3030, 4102 
CSE 1000, 2000, 3000''' 

all = [] 
for row in data.split('\n'): 
     klass,num_l = row.split(' ',1) 
     all.extend((klass,int(num)) for num in num_l.split(',')) 
0
data = '''\ 
MSE 2110, 3030, 4102 
CSE 1000, 2000, 3000''' 

def get_courses(data): 
    for row in data.splitlines(): 
     department, *numbers = row.replace(",", "").split() 
     for number in numbers: 
      yield department, number 

Questo darebbe un generatore per i codici del corso. È possibile creare un elenco con list() se necessario oppure è possibile scorrere direttamente su di esso.