Kurt Peek
Kurt Peek

Reputation: 57701

In PyParsing, how to define a setParseAction function to convert a list of strings to a list of integers?

I'm getting a ParseResult which is a list of strings which represent numbers, for example,

['160', '240', '320', '480', '640']

which I'd like to convert to the corresponding list of integers:

[160, 240, 320, 480, 640]

However, I'm having trouble figuring out the right function to put into the setParseAction method to achieve this result. Here is what I've tried so far (in Python 2):

In [1]: from pyparsing import *

In [2]: string = "densities: '160' '240' '320' '480' '640'"

In [3]: densities = LineStart() + "densities:" + OneOrMore(QuotedString(quoteChar="'"))("densities").setParseAction(lambda tokens: map(int, tokens))

In [4]: tokens = densities.parseString(string)

In [5]: tokens.asDict()
Out[5]: {'densities': [160]}

The parse action seems to only convert the first string to an integer. How can I modify this to achieve the desired list of integers? Or perhaps more generally: what do the tokens given to the function in setParseAction represent exactly?

Update

Following, Paul McGuire's comments and answer, I've tried using .setParseAction(tokenMap(int)), but the resulting named result densities is still only [160]:

In [1]: from pyparsing import *

In [2]: string = "densities: '160' '240' '320' '480' '640'"

In [3]: densities = LineStart() + "densities:" + OneOrMore(QuotedString(quoteCha
   ...: r="'"))("densities").setParseAction(tokenMap(int))

In [4]: tokens = densities.parseString(string)

In [5]: tokens.asDict()
Out[5]: {'densities': [160]}

I've also tried gaining more insight into the process using traceParseAction:

In [6]: densities = LineStart() + "densities:" + OneOrMore(QuotedString(quoteChar="'"))("densities").setParseAction(traceParseAction(tokenMap(int)))

In [7]: tokens = densities.parseString(string)
>>entering int(line: 'densities: '160' '240' '320' '480' '640'', 11, (['160', '240', '320', '480', '640'], {'densities': [(['160', '240', '320', '480', '640'], {})]}))
<<leaving int (ret: [160, 240, 320, 480, 640])

The ret shown here is the desired result, but somehow it doesn't appear to be the same as tokens.asDict()['densities']?

Upvotes: 4

Views: 977

Answers (1)

PaulMcG
PaulMcG

Reputation: 63762

I think the pyparsing_common.convertToInteger parse action will do the trick, which is implemented using pyparsing.tokenMap(int).

pyparsing.tokenMap will generate parse actions that take a function that will operate on a single token, and apply it to all the parsed tokens. More info on tokenMap here: https://pythonhosted.org/pyparsing/pyparsing-module.html#tokenMap

EDIT: Seems that Grouping is also required to get this to work:

densities = (LineStart()
             + "densities:"
             + Group(OneOrMore(QuotedString(quoteChar="'")).setParseAction(tokenMap(int)))("densities")
             )

Or, move the parse action inside the OneOrMore:

densities = (LineStart()
             + "densities:"
             + OneOrMore(QuotedString(quoteChar="'").setParseAction(tokenMap(int)))("densities")
             )

Upvotes: 3

Related Questions