pregunta pyparsing
-
19-09-2019 - |
Pregunta
Este 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
Estoy atascado en dos cuestiones:
1 - Cómo utilizar una función personalizada para analizar una muestra. Por ejemplo, si quería usar algo de lógica personalizada en lugar de una expresión regular para determinar si un número es un código postal. En lugar de:
zipcode = Regex( zipRE )
quizá:
zipcode = MyFunc()
2 - ¿Cómo se determina lo que analiza una cadena A. "80001" un análisis sintáctico de "código postal" pero ¿cómo puedo determinar esto utilizando pyparsing? No estoy analizar una cadena por su contenido sino simplemente para determinar qué tipo de consulta que es.
Solución
Su segunda pregunta es fácil, así que voy a responder a eso en primer lugar. Cambio de buscar resultados para asignar nombres a las diferentes expresiones:
query = ( zipcode("zip") | foo("foo") )
Ahora se puede llamar getName () en el resultado devuelto:
print t,"->", results, results.getName()
El 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
Si va a utilizar fooness o zipness del resultado de llamar a otra función, entonces se podría hacer esto en tiempo de análisis adjuntando una acción de análisis a sus foo y código postal expresiones:
# enclose zipcodes in '*'s, foos in '#'s
zipcode.setParseAction(lambda t: '*' + t[0] + '*')
foo.setParseAction(lambda t: '#' + t[0] + '#')
query = ( zipcode("zip") | foo("foo") )
Ahora da:
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
En su primera pregunta, no lo sé exactamente qué tipo de función que quiere decir. Pyparsing ofrece muchas más clases de análisis que sólo expresiones regulares (como Word, Palabra clave, literal, CaselessLiteral), y estás componiendo un analizador combinándolos con '+', '|', '^', '~', '@' y '*' operadores. Por ejemplo, si desea analizar para un número de seguridad social de Estados Unidos, pero no utilizar una expresión regular, se puede usar:
ssn = Combine(Word(nums,exact=3) + '-' +
Word(nums,exact=2) + '-' + Word(nums,exact=4))
Palabra partidos de "palabras" contiguos formados por los caracteres dados en su constructor, Combinar concatena las fichas coincidentes en una sola ficha.
Si usted quiere analizar para obtener una lista potencial de tales números, delimitado por '/' s, utilice:
delimitedList(ssn, '/')
o si había entre 1 y 3 tales números, sin delimters, utilice:
ssn * (1,3)
Y cualquier expresión puede tener resultados nombres o analizar las acciones unidos a ellos, para enriquecer aún más los resultados analizados, o la funcionalidad durante el análisis. Incluso se puede construir analizadores recursivos, tales como listas anidadas de paréntesis, expresiones aritméticas, etc, utilizando la clase Adelante.
Mi intención al escribir pyparsing era que esta composición de programas de análisis a partir de bloques de construcción básicos sería la forma principal para la creación de un programa de análisis. Fue sólo en una versión posterior que añadí expresión regular como (lo que, aunque era) la válvula último escape - si la gente no podía construir su programa de análisis, que podrían caer de nuevo en formato de expresiones regulares, lo que sin duda ha demostrado su poder sobre el tiempo.
O, como otro cartel sugiere, se puede abrir la fuente pyparsing, y la subclase una de las clases existentes, o escribir su propia, a raíz de su estructura. Aquí es una clase que se correspondería con los caracteres emparejados:
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")
Así que:
punc = r"~!@#$%^&*_-+=|\?/"
parser = OneOrMore(Word(alphas) | PairOf(punc))
print parser.parseString("Does ** this match @@@@ %% the parser?")
Da:
['Does', '**', 'this', 'match', '@@', '@@', '%%', 'the', 'parser']
(Tenga en cuenta la omisión del arrastre sencillo '?')
Otros consejos
Se puede usar código postal y comida por separado, de modo que usted sabe que uno de los partidos de cuerda.
zipresults = zipcode.parseString( t )
fooresults = foo.parseString( t )
No tengo el módulo pyparsing
, pero Regex
debe ser una clase, no una función.
Lo que puede hacer es subclase de ella y métodos de anulación según sea necesario para personalizar el comportamiento, a continuación, utilizar sus subclases en su lugar.