Home > Software engineering >  What would a python list (nested) parser look like in pyparsing?
What would a python list (nested) parser look like in pyparsing?

Time:12-30

I would like to understand how to use pyparsing to parse something like a nested Python list. This is a question to understand pyparsing. Solutions that circumvent the problem because the list of the example might look like JSON or Python itself should not prevent the usage of pyparsing.

So before people start throwing json and literal_eval at me let's consider a string and result that looks like this:

Input:
{1,2,3,{4,5}}
Expected Output (Python list):
[1,2,3,[4,5]]

I currently have this code but the output does not parse the nested list

import pyparsing


print(
    pyparsing.delimited_list(
        pyparsing.Word(pyparsing.nums) | pyparsing.nested_expr("{", "}")
    )
    .parse_string("{1,2,3,{4,5}}")
    .as_list()
)
# [['1,2,3,', ['4,5']]]

There is pretty much the same question here already but this one was circumvented by using json parsing: Python parse comma seperated nested brackets using Pyparsing

CodePudding user response:

You need to use a Forward reference, since your logic is recursive. It's impossible to use something you haven't defined before, hence the Forward object allows you to do just that:

expr = pyparsing.Forward()
expr <<= pyparsing.delimited_list(
    pyparsing.Word(pyparsing.nums) | pyparsing.nested_expr("{", "}", expr)
)

print(expr.parse_string("{1,2,3,{4,5}}").as_list())
# [['1', '2', '3', ['4', '5']]]

This answer also has another good example of how to use them.

CodePudding user response:

Thanks to the answer from Xiddoc I was able to slightly adjust the answer to also work when the expression starts with a list (no idea why the solution with nested_expr does not work)

import pyparsing as pp


expr = pp.Forward()
group_start, group_end = map(pp.Suppress, r"{}")

number = pp.Word(pp.nums).setParseAction(lambda s, l, t: int(t[0]))
nested_list = pp.Group(group_start   expr[...]   group_end)
expr <<= pp.delimited_list(number | nested_list)

print(expr.parse_string(r"{{1},2,3,{4,5}}", parse_all=True).as_list()[0])
# [[1],2,3,[4,5]]
  • Related