Thread: [Pyparsing] pyparsing svg - noob
Brought to you by:
ptmcg
From: Donn I. <don...@gm...> - 2007-11-08 09:55:20
|
Hi - I have been trying, but I need some help: Here's my test code to parse an SVG path element, can anyone steer me right? d1=""" M 209.12237 , 172.2415 L 286.76739 , 153.51369 L 286.76739 , 275.88534 L 209.12237 , 294.45058 L 209.12237 , 172.2415 z """ #Try it with no enters d1="""M 209.12237,172.2415 L 286.76739,153.51369 L 286.76739,275.88534 L 209.12237,294.45058 L 209.12237,172.2415 z """ #For later, has more commands d2=""" M 269.78326 , 381.27104 C 368.52151 , 424.27023 90.593578 , -18.581883 90.027729 , 129.28708 C 89.461878 , 277.15604 171.04501 , 338.27184 269.78326 , 381.27104 z """ ## word :: M, L, C, Z ## number :: group of numbers ## dot :: "." ## comma :: "," ## couple :: number dot number comma number dot number ## command :: word ## ## phrase :: command couple from pyparsing import Word, Literal, alphas, nums, Optional, OneOrMore command = Word("MLCZ") comma = Literal(",") dot = Literal(".") float = nums + dot + nums couple = float + comma + float phrase = OneOrMore(command + OneOrMore(couple | ( couple + couple ) ) ) print phrase print phrase.parseString(d1.upper()) Thanks \d |
From: Donn <don...@gm...> - 2007-11-08 10:24:31
|
Paul - thanks again for the accurate help. > phrase = OneOrMore(command("command") + Group(OneOrMore(couple))("coords") > ) Gives me an error: phrase = OneOrMore(command("command") + Group(OneOrMore(couple)) ("coords") ) TypeError: 'MatchFirst' object is not callable But I have not had a chance to get the latest pyparsing installed yet. Using your other suggestions seems to be working, so I'll keep hacking. Best, \d |
From: Ralph C. <ra...@in...> - 2007-11-08 10:29:21
|
Hi Donn, > from pyparsing import Word, Literal, alphas, nums, Optional, OneOrMore > > command = Word("MLCZ") > comma = Literal(",") > dot = Literal(".") > float = nums + dot + nums > couple = float + comma + float > > phrase = OneOrMore(command + OneOrMore(couple | ( couple + couple ) ) ) nums is just str('0123456789') so you're saying that you literally want '0123456789.0123456789' for every float. Change it to float = Word(nums) + dot + Word(nums) and all will be fine. You may find it's better to check you've the right number of couples depending on which command it is though, e.g. the grammar says move = Literal('M') + couple command = ... | move | ... Cheers, Ralph. |
From: Donn I. <don...@gm...> - 2007-11-08 10:43:45
|
Thanks for the help all. I've got a working version now. \d |
From: Donn <don...@gm...> - 2007-11-08 11:34:35
|
Paul, Sorry to bug you. Two things: 1. I am having a conceptual issue with the "list" returned by parseString. I can't seem to use it as a normal list. Mainly I like to while len(l)>0: and then l.pop(0) to process it but I can't seem to pop this list. 2. It seems the optional closing "Z" is being ignored. dot = Literal(".") float = Combine(Optional("-") + Word(nums) + dot + Word(nums)) command = oneOf("M L C Z") comma = Literal(",").suppress() couple = Group(float + comma + float) phrase = OneOrMore(command + Group(OneOrMore(couple)) ) #No C commands in this one... d1="""M 209.12237,172.2415 L 286.76739,153.51369 L 286.76739,275.88534 L 209.12237,294.45058 L 209.12237,172.2415 z """ paths = [] pl = phrase.parseString(d1.upper()) while len(pl) > 0: something = pl.pop(0) print something (I get : TypeError: 'str' object is not callable) I could use <for something in pl:> but since some of the coord lists are longer than others and not grouped ideally, it gets hairy. The ideal grouping would be something like this (I mix C and L commands) ['M', [float,float], 'C',[float,float,float,float,float,float], 'L',[float,float], 'Z'] So I can just pop them off one by one. \d |
From: Donn I. <don...@gm...> - 2007-11-08 13:46:04
|
Yeah, related to prev post, still no wiser. I'm having trouble getting a float out of a variable: It contains: Combine:({["-"] W:(0123...) "." W:(0123...)}) And it's type is: <class 'pyparsing.Combine'> But float(v) does not return 123.456 it returns the above. /d |
From: Paul M. <pa...@al...> - 2007-11-08 15:01:59
|
Donn - 1. Here is why you are having trouble getting floats out of a parsed string: float = ... whatever ... You are redefining the global float! Change float = Combine(Optional("-") + Word(nums) + dot + Word(nums)) to float_ = Combine(Optional("-") + Word(nums) + dot + Word(nums)) or realNum = Combine(Optional("-") + Word(nums) + dot + Word(nums)) or floatValue = Combine(Optional("-") + Word(nums) + dot + Word(nums)) Call it anything but float! 2. It seems the optional closing "Z" is being ignored. dot = Literal(".") float = Combine(Optional("-") + Word(nums) + dot + Word(nums)) command = oneOf("M L C Z") comma = Literal(",").suppress() couple = Group(float + comma + float) phrase = OneOrMore(command + Group(OneOrMore(couple)) ) Well this is because a phrase is made up of a repetition of (command + couple...), and there are no couples after the 'Z'. You later wrote: The ideal grouping would be something like this (I mix C and L commands) ['M', [float,float], 'C',[float,float,float,float,float,float], 'L',[float,float], 'Z'] Well why didn't you say so? :) In that case, Ralph Corderoy's suggestion works better: M_command = "M" + Group(couple) C_command = "C" + Group(couple + couple + couple) L_command = "L" + Group(couple) Z_command = "Z" command = M_command | C_command | L_command | Z_command phrase = OneOrMore(command) # what would generate your preferred list phrase = OneOrMore(Group(command)) # what I would recommend instead My recommended version of phrase makes each command its own nested list, like: [['M', [float,float]], ['C',[float,float,float,float,float,float]], ['L',[float,float]], ['Z']] Now you *can* iterate cleanly over this list, since the variable-length couple lists are enclosed in a list with their respective command letter. for command,couples in tokens[:-1]: print command print couples.asList() -- Paul |
From: Donn I. <don...@gm...> - 2007-11-08 13:50:05
|
> 2. It seems the optional closing "Z" is being ignored. Fixed this with + Optional(command) on the end. \d |
From: Paul M. <pa...@al...> - 2007-11-08 15:12:59
|
You are right, parseString really returns an object, ParseResults. ParseResults tries to behave much like a list, but adds some dict-like and object-like behavior too. I see I overlooked pop() in ParseResults' methods, I'll try to remember to include that in the next version. (You may have to resort to reading some documentation soon...) If you really, really, really want to pop your way through the tokens, you can convert the results to a list by using asList(), and then pop() away! I forgot to mention in the other e-mail: Another recommended technique is to do conversions like string-to-float during the parsing process itself, by adding a parse action. Let's assume you changed the variable name float to floatNum: floatNum = Combine(Optional("-") + Word(nums) + dot + Word(nums)) Now add: def convertToFloat(tokens): return float(tokens[0]) floatNum.setParseAction(convertToFloat) Or if you want to make this a one-liner (more compact, but a lot to take in at once when first learning): floatNum.setParseAction(lambda toks:float(toks[0])) Now when you process the resulting tokens, the floats will already be floating point numbers instead of strings, no need to convert them after-the-fact. -- Paul -----Original Message----- From: pyp...@li... [mailto:pyp...@li...] On Behalf Of Donn Sent: Thursday, November 08, 2007 5:39 AM To: Paul McGuire Cc: pyp...@li... Subject: Re: [Pyparsing] pyparsing svg - noob Paul, Sorry to bug you. Two things: 1. I am having a conceptual issue with the "list" returned by parseString. I can't seem to use it as a normal list. Mainly I like to while len(l)>0: and then l.pop(0) to process it but I can't seem to pop this list. 2. It seems the optional closing "Z" is being ignored. dot = Literal(".") float = Combine(Optional("-") + Word(nums) + dot + Word(nums)) command = oneOf("M L C Z") comma = Literal(",").suppress() couple = Group(float + comma + float) phrase = OneOrMore(command + Group(OneOrMore(couple)) ) #No C commands in this one... d1="""M 209.12237,172.2415 L 286.76739,153.51369 L 286.76739,275.88534 L 209.12237,294.45058 L 209.12237,172.2415 z """ paths = [] pl = phrase.parseString(d1.upper()) while len(pl) > 0: something = pl.pop(0) print something (I get : TypeError: 'str' object is not callable) I could use <for something in pl:> but since some of the coord lists are longer than others and not grouped ideally, it gets hairy. The ideal grouping would be something like this (I mix C and L commands) ['M', [float,float], 'C',[float,float,float,float,float,float], 'L',[float,float], 'Z'] So I can just pop them off one by one. \d ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ Pyparsing-users mailing list Pyp...@li... https://lists.sourceforge.net/lists/listinfo/pyparsing-users |
From: Donn <don...@gm...> - 2007-11-08 15:22:11
|
> object-like behavior too. I see I overlooked pop() in ParseResults' > methods, I'll try to remember to include that in the next version. Thanks. > (You may have to resort to reading some documentation soon...) I hear you. You've been magnificently patient with me :) > If you really, really, really want to pop your way through the tokens, you > can convert the results to a list by using asList(), and then pop() away! Great! It's an approach my mind likes - it lets me process things logically while in a loop that simply gets shorter as it loops! > floatNum.setParseAction(lambda toks:float(toks[0])) This and your other example are great ideas, I'll give 'em a whirl. I hope I don't hit many more walls, I'm actually aiming at other things and all this parsing kind of hit me over the head. I'll have to change gears and slow down. Thanks again. \d |
From: Donn I. <don...@gm...> - 2007-11-08 15:18:37
|
> float = ... whatever ... AAARRRGGGHHH! :) A Homer moment. > phrase = OneOrMore(Group(command)) # what I would recommend instead > My recommended version of phrase makes each command its own nested list, > like: > [['M', [float,float]], > ['C',[float,float,float,float,float,float]], > ['L',[float,float]], > ['Z']] > Your recc. phrase is producing this: M [['269.78326', '381.27104']] This is ok. C [['368.52151', '424.27023'], ['90.593578', '-18.581883'], ['90.027729', '129.28708']] This is 3 lists of 2 coords. Not a train smash, but not a single list of 6 coords. It's to do with the nature of a 'couple' I think. > for command,couples in tokens[:-1]: Now that is cool, but strange. I printed tokens[:-1] out and, oh boy, there's tupels in lists and dics too! Heck, as long as it works. \d |
From: Paul M. <pa...@al...> - 2007-11-08 15:24:43
|
I assumed that the couple always referred to an x-y coordinate pair, which is why I grouped them. If you don't wan the grouping, just make couple read: couple = floatNum + comma + floatNum and those inner groups will go away. -- Paul -----Original Message----- From: pyp...@li... [mailto:pyp...@li...] On Behalf Of Donn Ingle Sent: Thursday, November 08, 2007 9:23 AM To: pyp...@li... Subject: Re: [Pyparsing] pyparsing svg - noob > float = ... whatever ... AAARRRGGGHHH! :) A Homer moment. > phrase = OneOrMore(Group(command)) # what I would recommend instead > My recommended version of phrase makes each command its own nested > list, > like: > [['M', [float,float]], > ['C',[float,float,float,float,float,float]], > ['L',[float,float]], > ['Z']] > Your recc. phrase is producing this: M [['269.78326', '381.27104']] This is ok. C [['368.52151', '424.27023'], ['90.593578', '-18.581883'], ['90.027729', '129.28708']] This is 3 lists of 2 coords. Not a train smash, but not a single list of 6 coords. It's to do with the nature of a 'couple' I think. > for command,couples in tokens[:-1]: Now that is cool, but strange. I printed tokens[:-1] out and, oh boy, there's tupels in lists and dics too! Heck, as long as it works. \d ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ Pyparsing-users mailing list Pyp...@li... https://lists.sourceforge.net/lists/listinfo/pyparsing-users |