Pergunta

Esse código funciona:

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

Eu estou preso em duas questões:

1 - Como usar uma função personalizada para analisar um token. Por exemplo, se eu queria usar alguma lógica personalizada em vez de um regex para determinar se um número é um CEP. Em vez de:

zipcode = Regex( zipRE )

talvez:

zipcode = MyFunc()

2 - Como faço para determinar o que uma string analisa TO. "80001" Processa para "código postal", mas como faço para determinar isso usando pyparsing? Eu não sou analisar uma string para o seu conteúdo, mas simplesmente para determinar que tipo de consulta que é.

Foi útil?

Solução

A sua segunda pergunta é fácil, então eu vou responder a isso em primeiro lugar. Alterar consulta para nomes Resultados atribuir às diferentes expressões:

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

Agora você pode chamar getName () no resultado retornado:

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

Dar:

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 você estiver indo para usar fooness ou zipness do resultado de chamar uma outra função, então você pode fazer isso no momento da análise, anexando uma ação de análise aos seus foo e Cep expressões:

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

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

Agora 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

Para a sua primeira pergunta, eu não sei exatamente que tipo de função que você quer dizer. Pyparsing fornece muitas classes mais parsing do que apenas Regex (tais como Word, Palavra-chave, Literal, CaselessLiteral), e você compor seu analisador, combinando-os com '+', '|', '^', '~', '@' e operadores '*'. Por exemplo, se você quisesse analisar para um número de segurança social dos Estados Unidos, mas não usar um Regex, você poderia usar:

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

Word resultados para "palavras" contíguas composta de caracteres dados em seu construtor, Combine concatena os sinais combinados em um único token.

Se você quiser analisar para uma lista potencial de tais números, delimitado por '/' s, use:

delimitedList(ssn, '/')

ou se houvesse entre 1 e 3 desses números, sem delimters, uso:

ssn * (1,3)

E qualquer expressão podem ter nomes de resultados ou ações de análise que lhes são inerentes, a uma maior enriquecer os resultados analisada, ou a funcionalidade durante a análise. Você pode até mesmo construir analisadores recursiva, como listas aninhados de parênteses, expressões aritméticas, etc. usando a classe Forward.

O meu quando eu escrevi pyparsing intenção era que esta composição de analisadores de blocos básicos de construção seria a principal forma para a criação de um analisador. Foi apenas em uma versão posterior que eu adicionei Regex como (o que foi embora) a válvula de escape final - se as pessoas não podiam construir a sua parser, eles poderiam voltar a cair formato de regex, que tem definitivamente provado seu poder ao longo do tempo.

Ou, como um outro cartaz sugere, você pode abrir a fonte pyparsing, e uma subclasse das classes existentes, ou escreve sua própria, seguindo sua estrutura. Aqui é uma classe que iria corresponder para caracteres emparelhados:

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

Assim que:

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

Dá:

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

(Observe a omissão do arrastando single '?')

Outras dicas

Você pode usar CEP e foo separadamente, de modo que você sabe qual os jogos de cordas.

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

Eu não tenho o módulo pyparsing, mas Regex deve ser uma classe, não uma função.

O que você pode fazer é subclasse dele e métodos de substituição conforme necessário para o comportamento personalização, a seguir usar suas subclasses vez.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top