2010-02-06 10 views
1

Ce code fonctionne:pyparsing question

from pyparsing import * 

zipRE = "\d{5}(?:[-\s]\d{4})?" 
fooRE = "^\!\s+.*" 

zipcode = Regex(zipRE) 
foo = Regex(fooRE) 

query = (zipcode | foo) 



tests = [ "80517", "C6H5OH", "90001-3234", "! sfs" ] 

for t in tests: 
    try: 
     results = query.parseString(t) 
     print t,"->", results 
    except ParseException, pe: 
     print pe 

Je suis coincé sur deux questions:

1 - Comment utiliser une fonction personnalisée pour analyser un jeton. Par exemple, si je voulais utiliser une logique personnalisée au lieu d'une regex pour déterminer si un nombre est un code postal. Au lieu de:

zipcode = Regex(zipRE) 

peut-être:

zipcode = MyFunc() 

2 - Comment puis-je déterminer quelle chaîne parse TO. "80001" analyse en "zipcode" mais comment puis-je le déterminer en utilisant pyparsing? Je n'analyse pas une chaîne pour son contenu mais simplement pour déterminer quel type de requête elle est.

Répondre

2

Votre deuxième question est facile, alors je vais répondre à cette question en premier. Modifier requête pour attribuer des noms de résultats aux différentes expressions:

query = (zipcode("zip") | foo("foo")) 

Maintenant, vous pouvez appeler getName() sur le résultat retourné:

print t,"->", results, results.getName() 

Giving:

80517 -> ['80517'] zip 
Expected Re:('\\d{5}(?:[-\\s]\\d{4})?') (at char 0), (line:1, col:1) 
90001-3234 -> ['90001-3234'] zip 
! sfs -> ['! sfs'] foo 

Si vous allez Pour utiliser la fonction Fooess ou zipness du résultat pour appeler une autre fonction, vous pouvez le faire au moment de l'analyse en attachant une action d'analyse à vos expressions foo et zipcode:

# enclose zipcodes in '*'s, foos in '#'s 
zipcode.setParseAction(lambda t: '*' + t[0] + '*') 
foo.setParseAction(lambda t: '#' + t[0] + '#') 

query = (zipcode("zip") | foo("foo")) 

donne maintenant:

80517 -> ['*80517*'] zip 
Expected Re:('\\d{5}(?:[-\\s]\\d{4})?') (at char 0), (line:1, col:1) 
90001-3234 -> ['*90001-3234*'] zip 
! sfs -> ['#! sfs#'] foo 

Pour votre première question, je ne sais pas exactement quel genre de fonction que vous voulez dire. Pyparsing fournit beaucoup plus de classes d'analyse que juste Regex (comme Word, Keyword, Literal, CaselessLiteral), et vous composez votre analyseur en les combinant avec '+', '|', '^', '~', '@' et '*' les opérateurs. Par exemple, si vous voulez analyser un numéro de sécurité sociale des États-Unis, mais pas utiliser une expression régulière, vous pouvez utiliser:

ssn = Combine(Word(nums,exact=3) + '-' + 
     Word(nums,exact=2) + '-' + Word(nums,exact=4)) 

correspond à Word pour « mots » contigus composés des caractères donnés dans son constructeur, Unir concatène les jetons correspondants en un seul jeton.

Si vous voulez analyser pour obtenir une liste potentielle de ces chiffres, délimité par l «/des », utilisez:

delimitedList(ssn, '/') 

ou s'il y avait entre 1 et 3 de ces chiffres, sans delimters, utilisez:

ssn * (1,3) 

et toute expression peut avoir des noms de résultats ou analyser les actions qui leur sont rattachés, pour enrichir davantage les résultats ou la analysables fonctionnalité lors de l'analyse. Vous pouvez même créer des analyseurs récursifs, tels que des listes imbriquées de parenthèses, d'expressions arithmétiques, etc. à l'aide de la classe Forward. Mon intention quand j'ai écrit pyparsing était que cette composition de parseurs à partir des blocs de construction de base serait la forme primaire pour créer un analyseur. Ce n'est que dans une version ultérieure que j'ai ajouté Regex (ce que je pensais être) comme la valve d'échappement ultime - si les gens ne pouvaient pas construire leur analyseur, ils pourraient se rabattre sur le format regex. Ou, comme le suggère une autre affiche, vous pouvez ouvrir la source de pypars et sous-classer l'une des classes existantes, ou écrire la vôtre, en suivant leur structure. Voici une classe qui correspondrait à des caractères jumelés:

class PairOf(Token): 
    """Token for matching words composed of a pair 
     of characters in a given set. 
    """ 
    def __init__(self, chars): 
     super(PairOf,self).__init__() 
     self.pair_chars = set(chars) 

    def parseImpl(self, instring, loc, doActions=True): 
     if (loc < len(instring)-1 and 
      instring[loc] in self.pair_chars and 
      instring[loc+1] == instring[loc]): 
      return loc+2, instring[loc:loc+2] 
     else: 
      raise ParseException(instring, loc, "Not at a pair of characters") 

Alors que:

punc = r"[email protected]#$%^&*_-+=|\?/" 
parser = OneOrMore(Word(alphas) | PairOf(punc)) 
print parser.parseString("Does ** this match @@@@ %% the parser?") 

donne:

['Does', '**', 'this', 'match', '@@', '@@', '%%', 'the', 'parser'] 

(Notez l'omission du single de fuite '?')

+0

Merci pour cette réponse réfléchie. J'ai littéralement rêvé de ça hier soir. Je pense avoir un exemple pour illustrer ce que j'essaie de faire. L'un des exemples de pyparsing est l'analyse d'une adresse de rue. Et si je voulais étendre ce code pour analyser une ville et un État. Je pourrais analyser l'état en utilisant stateAbbreviation = oneOf ("" "AA AE AK AL ... (comme vous l'avez indiqué) .Mais si je veux analyser une ville en appelant une fonction dans un autre morceau de code, isStringPlacenmae (), ou peut-être un webservice qui me dira si une chaîne donnée est un nom de lieu ... – Art

+0

Quelques informations supplémentaires: J'écris un analyseur pour catégoriser les requêtes de recherche J'espère déterminer si une requête est une adresse, un code postal, un suivi nombre, expression mathématique, etc ... – Art

+0

Une action d'analyse peut être utile pour ajouter une validation au-delà de la simple correspondance d'expression Si l'autre logique échoue, l'action parse déclenche une ParseException, et l'analyseur la traitera comme un échec. l'expression originale. – PaulMcG

3

Vous pouvez utiliser zipcode et foo séparément, de sorte que vous sachiez lequel correspond à la chaîne.

zipresults = zipcode.parseString(t) 
fooresults = foo.parseString(t) 
2

Je n'ai pas le module pyparsing, mais Regex doit être une classe, pas une fonction. Ce que vous pouvez faire est sous-classe et remplacer les méthodes nécessaires pour personnaliser le comportement, puis utilisez vos sous-classes à la place.