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]]