Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass values to pyparsing parseactions?

Specifically I want to write a generic parseaction function which will verify ranges of numbers. I want to pass a min & max to the function. Is this possible ?

like image 450
Frankie Ribery Avatar asked May 09 '11 10:05

Frankie Ribery


1 Answers

Use a closure, something like this:

def rangeCheck(minval=None, maxval=None):
    if minval is None and maxval is None:
        # this exception occurs not at parse time, but while defining the grammar
        raise ValueError("minval or maxval must be specified")

    def rangeCheckParseAction(string, loc, tokens):
        parsedval = tokens[0]
        if minval is not None:
            if maxval is not None:
                valid = minval <= parsedval <= maxval
            else:
                valid = minval <= parsedval
        else:
            if maxval is not None:
                valid = parsedval <= maxval

        if not valid:
            raise ParseException(string, loc, 
                    "value not in range (%s,%s)" % (minval, maxval))

    return rangeCheckParseAction

integer = Combine(Optional(oneOf("+ -")) + Word(nums))
integer.setParseAction(lambda t:int(t[0]))

month = integer.copy().addParseAction(rangeCheck(1,12))
day = integer.copy().addParseAction(rangeCheck(1,31))
year = integer.copy().addParseAction(rangeCheck(2000))

SLASH = Suppress('/')
dateExpr = year + SLASH + month + SLASH + day
print dateExpr.parseString("2011/5/8")
print dateExpr.parseString("1999/12/31")

Prints:

[2011, 5, 8]
Traceback (most recent call last):
  File "rangeCheck.py", line 21, in <module>
    print dateExpr.parseString("1999/12/31")
  File "c:\python26\lib\site-packages\pyparsing.py", line 1100, in parseString
    raise exc
pyparsing.ParseException: value not in range (2000,None) (at char 0), (line:1, col:1)

Of course, a better parse action would be to validate the entire date - this current parser would accept '2000/2/31', for instance.

Here's an exercise for the reader: write a parse action to convert the parsed date tokens to a datetime, and then use the exact same rangeCheck parse action to verify that a given time stamp is within a permitted range of datetime values.

(Note that I did not include the string->int conversion in rangeCheck, but broke this up into 2 separate parse actions, so rangeCheck can be used to validate any type that supports < and >. Just be sure to call addParseAction vs. setParseAction, so that pyparsing will continue to do the integer conversion parse action first.)

You can find other examples like this in pyparsing itself - withAttribute is such a method that creates a parse action to verify that an XML or HTML tag has a particular attribute, optionally with a particular value.

like image 170
PaulMcG Avatar answered Nov 19 '22 20:11

PaulMcG