Domanda

Questo codice funziona:

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

Sono bloccato su due questioni:

1 - Come utilizzare una funzione personalizzata per analizzare un token. Per esempio, se volessi usare un po 'di logica personalizzata invece di una regex per determinare se un numero è un codice postale. Invece di:

zipcode = Regex( zipRE )

forse:

zipcode = MyFunc()

2 - Come faccio a determinare ciò che una stringa analizza TO. "80001" analizza a "codice postale" ma come faccio a determinare questo utilizzando pyparsing? Non sto parsing di una stringa per i suoi contenuti, ma semplicemente per determinare quale tipo di interrogazione che è.

È stato utile?

Soluzione

La seconda domanda è facile, quindi dovrò rispondere a questa prima. Modificare query per assegnare i nomi ai risultati le diverse espressioni:

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

Ora è possibile chiamare getName () sul risultato restituito:

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

Dare:

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

Se avete intenzione di utilizzare fooness o zipness del risultato per chiamare un'altra funzione, allora si potrebbe fare questo in fase di analisi ed accompagnato da un'azione di analisi per i tuoi Foo e CAP espressioni:

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

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

Ora dà:

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

Per la vostra prima domanda, io non esattamente sapere che tipo di funzione che si intende. Pyparsing fornisce molte più classi di analisi di un semplice Regex (come Word, parola chiave, letterale, CaselessLiteral), e di comporre la vostra parser combinandole con '+', '|', '^', '~', '@' e '*' operatori. Per esempio, se si voleva analizzare per un numero di sicurezza sociale degli Stati Uniti, ma non utilizzare un Regex, è possibile utilizzare:

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

Parola corrisponde per contigui "parole" composte dei caratteri dati nel suo costruttore, Unire concatena i gettoni abbinati in un unico token.

Se si voleva analizzare per un potenziale elenco di tali numeri, delimitato da '/' s, uso:

delimitedList(ssn, '/')

o se ci fossero tra 1 e 3 tali numeri, senza delimters, uso:

ssn * (1,3)

E qualsiasi espressione può avere risultati nomi o analizzare le azioni ad essi connessi, per arricchire ulteriormente i risultati analizzati, o la funzionalità durante l'analisi. Si può anche costruire parser ricorsive, come le liste nidificate di parentesi, espressioni aritmetiche, ecc utilizzando la classe di andata.

Il mio intento quando ho scritto pyparsing era che questa composizione del parser da blocchi di costruzione di base sarebbe la forma primaria per la creazione di un parser. E 'stato solo in una versione successiva che ho aggiunto Regex come (quello che mi era) la valvola di sfogo finale - se le persone non riuscivano a costruire la loro parser, potrebbero ripiegare su formato di espressione regolare, che ha definitivamente dimostrato la sua potenza nel tempo.

In alternativa, come suggerisce un altro manifesto, è possibile aprire la fonte pyparsing, e sottoclasse una delle classi esistenti, o lascia la tua, seguendo la loro struttura. Ecco una classe che sarebbe partita per i caratteri appaiati:

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")

In modo che:

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

si ottiene:

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

(Notare l'omissione del trailing singolo '?')

Altri suggerimenti

Si potrebbe utilizzare codice postale e foo separatamente, in modo che si sa che una delle partite di stringa.

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

Non ho il modulo pyparsing, ma Regex deve essere una classe, non una funzione.

Che cosa si può fare è sottoclasse da esso e metodi di override, come richiesto per personalizzare il comportamento, quindi utilizzare le sottoclassi, invece.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top