RE: [Pyparsing] Combining strings
Brought to you by:
ptmcg
From: Paul M. <pa...@al...> - 2006-03-24 13:59:40
|
Mike - Welcome to the world of pyparsing! This is a good start at implementing a little shell language (perhaps to provide a safe scripting environment?). Your program has just about all the necessary pieces to solve your problem. Actually, I think most of the solution lies in *removing* code! I went through 2 stages in looking at your problem. First I thought of doing a 2-pass parse on this input: first pass to just do the symbol substitution, then the second pass to interpret the modified command string. Second stage was to incorporate the symbol substitution into the overall command parsing, as your program had been doing. I'm still deciding which approach I like better, maybe we'll come back to that. So in stage 1, I looked just at your pyvar definition. (It looks like you want to replace '%(xxx)' or '%xxx' with the contents of some previously defined value 'xxx'): pyvar = Combine( Optional(printables) + Literal('%').suppress() + Optional('(').suppress() + Word(variable) + Optional(')').suppress() + Optional(printables) ) There's too much included in this definition. I suspect you started with something simple, then tried to add the leading and trailing Optional(printables) when your pyvar was embedded in something larger, like a path. If we leave pyvar this way, then the parse action will drop the surrounding data on the floor. (This COULD be fixed by updating the parse action, but I'd prefer to keep pyvar to be just about the '%xxx' syntax.) pyvar = Combine( Literal('%').suppress() + Optional('(').suppress() + Word(variable) + Optional(')').suppress() ) Your input string is: echo /home/%(user)/path/%(prog)/bin/%prog With your simplified pyvar, you can just use it to do the variable substitution in a first pass: print pyvar.transformString(cmdstring) Prints out: echo /home/mgmiller/path/foo/bin/foo So if you add: cmdstring = pyvar.transformString(cmdstring) This will do all the symbol substitution, up front. Now your definition of statement can focus on what your intended command syntax should be: statement = keyword + ZeroOrMore(args) Which parses as you expect, print statement.parseString(cmdstring) Gives: ['echo', '/home/mgmiller/path/foo/bin/foo'] I am a fan of using results names, so I jazzed up your statement definition to read: statement = ( keyword.setResultsName("command") + ZeroOrMore(args).setResultsName("args") ) Which now allows me to write: inputCmd = statement.parseString(cmdstring) print inputCmd.command print inputCmd.args And I get: echo ['/home/mgmiller/path/foo/bin/foo'] Stage 2 required changing around the definition of args, to comprehend that it migh include some embedded pyvars: args = Combine( OneOrMore( Word(alphanums + '_-=/"\'') | pyvar ) ) This give us a working single pass parser, but I'm not keen on this 'pollution' of the args definition. This grammar is fairly simple, so it's not a big deal. But in general, I think variable or macro substitution needs to happen in its own transformation pass first - otherwise, the grammar will need to include lots of "| pyvar" type elements, since you can't predict where they will show up. By separating into two passes, the substitution part is very simple and clean, and the application grammar is simple and clean. Please check out the adventure game presentation I gave at the last PyCon - you can get the source code and see how I implemented a Command pattern to structure the execution of the parsed commands. Good luck! -- Paul -----Original Message----- From: pyp...@li... [mailto:pyp...@li...] On Behalf Of pyp...@mg... Sent: Friday, March 24, 2006 3:56 AM To: pyp...@li... Subject: [Pyparsing] Combining strings Hi, I'm trying to get a string back in one piece and the Combine class doesn't seem to be working. I'm not sure how to fix it. Can anyone help? Here's the output: echo /home/%(user)/apps/%(prog)/bin/%prog ['echo', '/home/', 'mgmiller', '/apps/', 'foo', '/bin/', 'foo'] I'd like to get the path back as one string ... how can I do that? Thanks if you can help, -Mike ---------------------- #!/bin/env python from pyparsing import * import string, os namespace = { 'a': 5, 'user':'mgmiller', 'prog':'foo' } cmdstring = r''' echo /home/%(user)/path/%(prog)/bin/%prog ''' def getpyvar(s, loc, match): 'return a python type variable from our own namespace' if namespace.has_key(match[0]): return namespace[match[0]] # define grammar keyword = oneOf('alias dir echo ver') args = Word(alphanums + '_-=/"\'') variable = alphas + '_' # expansions pyvar = Combine( Optional(printables) + Literal('%').suppress() + Optional('(').suppress() + Word(variable) + Optional(')').suppress() + Optional(printables) ) pyvar.setParseAction(getpyvar) statement = ( keyword + ZeroOrMore(pyvar | args) ) print cmdstring print statement.parseString(cmdstring) ---------------------- -Mike ------------------------------------------------------------- Mike Miller Earth, Sol, Orion Arm, Milky Way ------------------------------------------------------- This SF.Net email is sponsored by xPML, a groundbreaking scripting language that extends applications into web and mobile media. Attend the live webcast and join the prime developer group breaking into this new coding territory! http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642 _______________________________________________ Pyparsing-users mailing list Pyp...@li... https://lists.sourceforge.net/lists/listinfo/pyparsing-users |