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 ?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With