Search code examples
pythonparsingexpression-trees

How do I approach parsing and tree processing tasks in python? (representing rhythm)


I have a private notation for musical rhythm, which looks like, e.g. --(---)- for beat, beat, triplet, beat. Brackets divide a single beat into as many parts as they contain.

It's recursive, so e.g. --((--)(--))- means the same as --(----)-

I'm trying parse such strings and turn them into note durations, and I'm finding it surprisingly hard in python.

An example should go something like:

string="--(-(--))-(--(--))---(--)(-)"
->
tree=[1,1,[1,[1,1]],1,[1,1,[1,1]],1,1,1,[1,1],[1]]
->
inversedurations= [1,1,2,4,4,1,3,3,6,6,1,1,1,2,2,1]

pyparsing seems to do the actual hard bit quite easily:

import pyparsing
parsed=(pyparsing.nestedExpr().parseString("("+string+")").asList())[0]

['--', ['-', ['--']], '-', ['--', ['--']], '---', ['--'], ['-']]

but when it comes to turning that into tree above, just replacing the string '--' with 1,1 I'm trying to write recursions and map and concatenate lists like I would in lisp but I'm just getting stuck.

Can anyone show me a nice way to do such things in python? Does the lisp style go over easily, or are there clever things with generators and comprehensions to do instead?


Solution

  • I'm not sure if I've understood your question correctly. Do you want to convert the output from pyparsing to tree structure as stated in your question? If yes, you can do something like this:

    lst = ['--', ['-', ['--']], '-', ['--', ['--']], '---', ['--'], ['-']]
    
    def convert(lst):
        for item in lst:
            if isinstance(item, str):
                yield from (1 for i in item)
            else:
                yield [*convert(item)]
    
    print(list(convert(lst)))
    

    Prints:

    [1, 1, [1, [1, 1]], 1, [1, 1, [1, 1]], 1, 1, 1, [1, 1], [1]]