2010-05-30 12 views
1

Je suis en train d'analyser des phrases comme "CS 2110 ou INFO 3300". Je voudrais sortir un format comme:PyParsing: tous les jetons ne sont pas passés à setParseAction()

[[("CS" 2110)], [("INFO", 3300)]] 

Pour ce faire, je pensais que je pouvais utiliser setParseAction(). Cependant, les déclarations contenues dans printstatementParse() suggèrent que seuls les derniers jetons sont passés en réalité:

>>> statement.parseString("CS 2110 or INFO 3300") 
Match [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}] at loc 7(1,8) 
string CS 2110 or INFO 3300 
loc: 7 
tokens: ['INFO', 3300] 
Matched [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}] -> ['INFO', 3300] 
(['CS', 2110, 'INFO', 3300], {'Course': [(2110, 1), (3300, 3)], 'DeptCode': [('CS', 0), ('INFO', 2)]}) 

Je m'y attendais tous les jetons à passer, mais il est seulement ['INFO', 3300]. Est-ce que je fais quelque chose de mal? Ou y a-t-il un autre moyen de produire la sortie désirée?

Voici le code pyparsing: (! Vous établissiez seulement sur la Optional)

from pyparsing import * 

def statementParse(str, location, tokens): 
    print "string %s" % str 
    print "loc: %s " % location 
    print "tokens: %s" % tokens 

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

OR_CONJ = Suppress("or") 

COURSE_NUMBER.setParseAction(lambda s, l, toks : int(toks[0])) 

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

statement = course + Optional(OR_CONJ + course).setParseAction(statementParse).setDebug() 

Répondre

2

Afin de garder les bits de jeton de « CS 2110 » et « INFO 3300" , je vous enveloppez votre définition bien sûr dans un groupe:

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

Il semble aussi que vous chargez la tête sur à l'analyse syntaxique sur une sorte d'expression de recherche, comme « x et y ou z ». Il y a une certaine subtilité à ce problème, et je vous suggère de vérifier quelques-uns des exemples sur le wiki pyparsing sur la façon de construire ces types d'expressions. Sinon, vous finirez avec un nid d'oiseau de Optional("or" + this) et ZeroOrMore( "and" + that) pièces. En dernière chance, vous pouvez même simplement utiliser quelque chose avec operatorPrecedence, comme:

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

courseSearch = operatorPrecedence(course, 
    [ 
    ("not", 1, opAssoc.RIGHT), 
    ("and", 2, opAssoc.LEFT), 
    ("or", 2, opAssoc.LEFT), 
    ]) 

(. Vous devrez peut-être télécharger la dernière version à partir du 1.5.3 SVN SourceForge pour que cela fonctionne)

+0

Oui «Charger de front» est un très bon moyen de décrire ce que je fais. Merci pour le pointeur vers l'exemple sur le wiki. –

2

fonctionne mieux si vous définissez l'action Parse sur deuxcourse et Optional:

>>> statement = (course + Optional(OR_CONJ + course)).setParseAction(statementParse).setDebug() 
>>> statement.parseString("CS 2110 or INFO 3300")  

donne

Match {Re:('[A-Z]{2,}') Re:('[0-9]{4}') [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}]} at loc 0(1,1) 
string CS 2110 or INFO 3300 
loc: 0 
tokens: ['CS', 2110, 'INFO', 3300] 
Matched {Re:('[A-Z]{2,}') Re:('[0-9]{4}') [{Suppress:("or") Re:('[A-Z]{2,}') Re:('[0-9]{4}')}]} -> ['CS', 2110, 'INFO', 3300] 
(['CS', 2110, 'INFO', 3300], {'Course': [(2110, 1), (3300, 3)], 'DeptCode': [('CS', 0), ('INFO', 2)]}) 

bien que je soupçonne ce que vous voulez réellement est de définir l'action d'analyse sur chaque cours, pas sur la déclaration :

>>> statement = course + Optional(OR_CONJ + course) 
>>> statement.parseString("CS 2110 or INFO 3300")        Match {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} at loc 0(1,1) 
string CS 2110 or INFO 3300 
loc: 0 
tokens: ['CS', 2110] 
Matched {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} -> ['CS', 2110] 
Match {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} at loc 10(1,11) 
string CS 2110 or INFO 3300 
loc: 10 
tokens: ['INFO', 3300] 
Matched {Re:('[A-Z]{2,}') Re:('[0-9]{4}')} -> ['INFO', 3300] 
(['CS', 2110, 'INFO', 3300], {'Course': [(2110, 1), (3300, 3)], 'DeptCode': [('CS', 0), ('INFO', 2)]})