qua qua - 7 months ago 31
Python Question

Parsing a lisp file with Python

I have the following lisp file, which is from the UCI machine learning database. I would like to convert it into a flat text file using python. A typical line looks like this:

(1 ((st 8) (pitch 67) (dur 4) (keysig 1) (timesig 12) (fermata 0))((st 12) (pitch 67) (dur 8) (keysig 1) (timesig 12) (fermata 0)))


I would like to parse this into a text file like:

time pitch duration keysig timesig fermata
8 67 4 1 12 0
12 67 8 1 12 0


Is there a python module to intelligently parse this? This is my first time seeing lisp.

Answer

As shown in this answer, pyparsing appears to be the right tool for that:

inputdata = '(1 ((st 8) (pitch 67) (dur 4) (keysig 1) (timesig 12) (fermata 0))((st 12) (pitch 67) (dur 8) (keysig 1) (timesig 12) (fermata 0)))'

from pyparsing import OneOrMore, nestedExpr

data = OneOrMore(nestedExpr()).parseString(inputdata)
print data

# [['1', [['st', '8'], ['pitch', '67'], ['dur', '4'], ['keysig', '1'], ['timesig', '12'], ['fermata', '0']], [['st', '12'], ['pitch', '67'], ['dur', '8'], ['keysig', '1'], ['timesig', '12'], ['fermata', '0']]]]

For the completeness' sake, this is how to format the results (using texttable):

from texttable import Texttable

tab = Texttable()
for row in data.asList()[0][1:]:
    row = dict(row)
    tab.header(row.keys())
    tab.add_row(row.values())
print tab.draw()
+---------+--------+----+-------+-----+---------+
| timesig | keysig | st | pitch | dur | fermata |
+=========+========+====+=======+=====+=========+
| 12      | 1      | 8  | 67    | 4   | 0       |
+---------+--------+----+-------+-----+---------+
| 12      | 1      | 12 | 67    | 8   | 0       |
+---------+--------+----+-------+-----+---------+

To convert that data back to the lisp notation:

def lisp(x):
    return '(%s)' % ' '.join(lisp(y) for y in x) if isinstance(x, list) else x

d = lisp(d[0])