473,324 Members | 2,535 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 software developers and data experts.

parsing string to a list of objects - help!

Hi, I really hope someone can help me -- I'm stuck.

I have written three versions of code over a week and still can't get past
this problem, it's blocking my path to getting other code written.

This might be a little hairy, but I'll try to keep it short.

Situation:
I want to pass a string to a function which will parse it and generate
objects in a list.
Each object is a "property" which keeps members like x,y,r,g,b etc.
Each element in the final list describes a frame in an animation.

I want to be able to pass only the properties of key moments (key frames) in
time to the function. Along with that is passed the *way* each moment
changes into the next.

The form I am using is like this:
t=Thing()
t.propLayout("#---#---#==_##_")
prop1 = Property(x=10,y=10,r=1,g=1,b=1,a=0)
prop2 = Property(x=20,y=10,r=0,g=0,b=1,a=1)
prop3 = Property(x=10,y=100,r=1,g=1,b=1,a=1)
prop4 = Property(x=100,y=200,r=1,g=1,b=1,a=1)
t.setProps(prop1,prop1,prop2,prop3,prop4)

So setProps is the parser and it creates a proplist within t.

My short-hand for this:
# is a property
- is a 'tween' (where the property before it influences it)
= is a property exactly the same as the one before it.
_ (underscore) is a blank frame

Things like this can be expressed:
1234567890123
#---#--#===_#
(4 keyframes, #'s. 13 frames, lifetime.)
In words that would say:
Frame 1, make a property.
Frame 2 to 4 tweening : copy previous property (from 1) and advance the
members by the average (calculated by getting the range between 1 and 5 and
going through each member variable (x,y,z,r,g,b) and dividing etc. This
means looking ahead.)
Frame 5, make a property
Frame 6 to 7 tweening.
Frame 8, make a property
Frame 9 to 11, copy property from 8
Frame 12, make a blank
Frame 13, make a property.

So, the animation will proceed: Start at 1, move/morph to 5, move/morph to
8, remain static to 11, go away for 12 and appear somewhere at 13.

It seems so simple, but I just cannot nail it down. Each time I end up with
a mess of string[index] and if else tests within while loops that seem to
work until I get to a test string that breaks it all.

I'm sure there must be a better way to formalize this little 'language' and
break it down into a list of property objects that exactly describes the
string -- catching user errors too.

The rules:
Tweens : must start and end in # signs: #----#
Static : must start with a # : #===
No other chars can be within a range: #==_= is bad. #--=--# is bad.

Odds:
Singles: things like ### are valid. This means each is a frame somewhere,
implying they will jump around (i.e. not be statics)
Blanks : are simple - they are properties for every underscore

I have glanced around at parsing and all the tech-speak confuses the heck
out of me. I am not too smart and would appreciate any help that steers
away from cold theory and simply hits at this problem.

Donn.

Nov 5 '07 #1
7 2351
On Nov 5, 3:00 am, Donn Ingle <donn.in...@gmail.comwrote:
>
I have glanced around at parsing and all the tech-speak confuses the heck
out of me. I am not too smart and would appreciate any help that steers
away from cold theory and simply hits at this problem.
Donn -

Here is a pyparsing version that I hope is fairly easy-to-read and
tech-speak free:

from pyparsing import *

frame = Literal("#")
tween = Word("-") # that is, it is a "word" composed of 1 or more -'s
copy = Literal("=")
blank = Literal("_")

animation = OneOrMore((frame + Optional(
(tween + FollowedBy(frame)) |
OneOrMore(copy | blank) ) ) )

test = "#---#--#===_#"

print animation.parseString(test)

This prints the following:

['#', '---', '#', '--', '#', '=', '=', '=', '_', '#']

>From here, the next step would be to define classes that these matched
tokens could be converted to. Pyparsing allows you to attach a method
to individual expressions using setParseAction - if you pass a class
instead of a method, then class instances are returned. For these
tokens, you could write:

class Prop(object):
def __init__(self,tokens):
pass

class Tween(object):
def __init__(self,tokens):
self.tween = tokens[0]
self.tweenLength = len(self.tween)

class CopyPrevious(object):
def __init__(self,tokens):
pass

class Blank(object):
def __init__(self,tokens):
pass

frame.setParseAction(Prop)
tween.setParseAction(Tween)
copy.setParseAction(CopyPrevious)
blank.setParseAction(Blank)

And now calling animation.parseString(test) returns a sequence of
objects representing the input string's frames, tweens, etc.:

[<__main__.Prop object at 0x00B9D8F0>, <__main__.Tween object at
0x00BA5390>, <__main__.Prop object at 0x00B9D9B0>, <__main__.Tween
object at 0x00BA55F0>, <__main__.Prop object at 0x00BA5230>,
<__main__.CopyPrevious object at 0x00BA58F0>, <__main__.CopyPrevious
object at 0x00BA59D0>, <__main__.CopyPrevious object at 0x00BA5AB0>,
<__main__.Blank object at 0x00BA5B70>, <__main__.Prop object at
0x00BA5510>]

Now you can implement behavior in these 4 classes to implement the
tweening, copying, etc. behavior that you want, and then walk through
this sequence invoking this animation logic.

-- Paul
Nov 5 '07 #2
Wow Paul, you have given me much to chew. I'll start testing it in my slow
way -- it looks so simple!

Thank you.
\d

Nov 5 '07 #3
Paul,
I quickly slapped your example into a py file for a first-glance test and
the first part works, but the second gives me the error below. Could I have
an old version of pyparser? I will dig into it anyway, just being lazy :)

code:
from pyparsing import *

frame = Literal("#")
tween = Word("-") # that is, it is a "word" composed of 1 or more -'s
copy = Literal("=")
blank = Literal("_")

animation = OneOrMore((frame + Optional(
(tween + FollowedBy(frame)) |
OneOrMore(copy | blank) ) ) )

test = "#---#--#===_#"

print animation.parseString(test)

class Prop(object):
def __init__(self,tokens):
pass

class Tween(object):
def __init__(self,tokens):
self.tween = tokens[0]
self.tweenLength = len(self.tween)

class CopyPrevious(object):
def __init__(self,tokens):
pass

class Blank(object):
def __init__(self,tokens):
pass

frame.setParseAction(Prop)
tween.setParseAction(Tween)
copy.setParseAction(CopyPrevious)
blank.setParseAction(Blank)
animation.parseString(test)

result:
containers:$ python parser.py
['#', '---', '#', '--', '#', '=', '=', '=', '_', '#']
Traceback (most recent call last):
File "parser.py", line 39, in ?
animation.parseString(test)
File "/usr/lib/python2.4/site-packages/pyparsing.py", line 620, in
parseString
loc, tokens = self.parse( instring.expandtabs(), 0 )
File "/usr/lib/python2.4/site-packages/pyparsing.py", line 562, in parse
loc,tokens = self.parseImpl( instring, loc, doActions )
File "/usr/lib/python2.4/site-packages/pyparsing.py", line 1768, in
parseImpl
loc, tokens = self.expr.parse( instring, loc, doActions )
File "/usr/lib/python2.4/site-packages/pyparsing.py", line 562, in parse
loc,tokens = self.parseImpl( instring, loc, doActions )
File "/usr/lib/python2.4/site-packages/pyparsing.py", line 1390, in
parseImpl
loc, resultlist = self.exprs[0].parse( instring, loc, doActions )
File "/usr/lib/python2.4/site-packages/pyparsing.py", line 588, in parse
tokens = self.parseAction( instring, tokensStart, retTokens )
TypeError: __init__() takes exactly 2 arguments (4 given)
Nov 5 '07 #4
Wow Paul, you have given me much to chew. I'll start testing it in my slow
way -- it looks so simple!

Thank you.
\d

Nov 5 '07 #5
Paul,
frame = Literal("#")
tween = Word("-") # that is, it is a "word" composed of 1 or more -'s
copy = Literal("=")
blank = Literal("_")

animation = OneOrMore((frame + Optional(
(tween + FollowedBy(frame)) |
OneOrMore(copy | blank) ) ) )
I found that this form insists on having a # in char 0. How could it be
changed to take a bunch of blanks before the first frame?
____# ?

I have tried:
animation = OneOrMore(
Optional ( blank | frame ) +
Optional( (tween + FollowedBy(frame) ) | OneOrMore(copy | blank) )
)

And permutations thereof, but it goes into a black hole.

\d

Nov 5 '07 #6
Donn -

The exception you posted is from using an old version of pyparsing.
You can get the latest from SourceForge - if you download the Windows
binary install, please get the docs package too. It has a full doc
directory (generated with epydoc), plus example scripts for a variety
of applications. There is also an e-book available from O'Reilly that
just came out in early October.

To add an optional lead-in of one or more blanks,just change animation
from:

animation = OneOrMore((frame + Optional(
(tween + FollowedBy(frame)) |
OneOrMore(copy | blank) ) ) )

to:

animation = Optional(OneOrMore(blank)) + \
OneOrMore((frame + Optional(
(tween + FollowedBy(frame)) |
OneOrMore(copy | blank) ) ) )

I modified your test, and there were no problems parsing strings with
and without the leading '_'s.

-- Paul

Nov 5 '07 #7
Here is a first cut at processing the parsed objects, given a list of
Property objects representing the frames at each '#':

class Property(object):
def __init__(self,**kwargs):
self.__dict__.update(kwargs)

def copy(self):
return Property(**self.__dict__)

@staticmethod
def tween(prev,next,n,i):
dt = 1.0/(n+1)
x = prev.x + (next.x-prev.x)*dt*(i+1)
y = prev.y + (next.y-prev.y)*dt*(i+1)
r = prev.r + (next.r-prev.r)*dt*(i+1)
g = prev.g + (next.g-prev.g)*dt*(i+1)
b = prev.b + (next.b-prev.b)*dt*(i+1)
a = prev.a + (next.a-prev.a)*dt*(i+1)
return Property(x=x,y=y,r=r,g=g,b=b,a=a)

@staticmethod
def makeBlank():
return Property(x=0,y=0,r=0,g=0,b=0,a=0)

def __repr__(self):
return "Property(x=%(x).3f, y=%(y).3f, r=%(r).3f, g=%(g).3f, b=
%(b).3f, a=%(a).3f)" % self.__dict__
def makeAllFrames(propFrameList, animationList):
ret = []
propFrameIndex = 0
for animIndex,animObj in enumerate(animationList):
if isinstance(animObj, Prop):
ret.append( propFrameList[propFrameIndex] )
propFrameIndex += 1
if isinstance(animObj, Blank):
ret.append( Property.makeBlank() )
if isinstance(animObj, CopyPrevious):
ret.append( ret[-1].copy() )
if isinstance(animObj, Tween):
# compute delta x,y,r,g,b,a between prev frame and next
frame
prev = propFrameList[propFrameIndex-1]
next = propFrameList[propFrameIndex]
numFrames = animObj.tweenLength
print `prev`, `next`
tweens = [ Property.tween(prev,next,numFrames,i) for i in
range(numFrames) ]
ret += tweens
return ret

prop1 = Property(x=10,y=10,r=1,g=1,b=1,a=0)
prop2 = Property(x=20,y=10,r=0,g=0,b=1,a=1)
prop3 = Property(x=10,y=100,r=1,g=1,b=1,a=1)
prop4 = Property(x=100,y=200,r=1,g=1,b=1,a=1)
propFrames = [ prop1, prop2, prop3, prop4 ]

allFramesList = makeAllFrames( propFrames, animation.parseString("#---
#--#===_#") )
from pprint import pprint
pprint( allFramesList )

Gives:
[Property(x=10.000, y=10.000, r=1.000, g=1.000, b=1.000, a=0.000),
Property(x=12.500, y=10.000, r=0.750, g=0.750, b=1.000, a=0.250),
Property(x=15.000, y=10.000, r=0.500, g=0.500, b=1.000, a=0.500),
Property(x=17.500, y=10.000, r=0.250, g=0.250, b=1.000, a=0.750),
Property(x=20.000, y=10.000, r=0.000, g=0.000, b=1.000, a=1.000),
Property(x=16.667, y=40.000, r=0.333, g=0.333, b=1.000, a=1.000),
Property(x=13.333, y=70.000, r=0.667, g=0.667, b=1.000, a=1.000),
Property(x=10.000, y=100.000, r=1.000, g=1.000, b=1.000, a=1.000),
Property(x=10.000, y=100.000, r=1.000, g=1.000, b=1.000, a=1.000),
Property(x=10.000, y=100.000, r=1.000, g=1.000, b=1.000, a=1.000),
Property(x=10.000, y=100.000, r=1.000, g=1.000, b=1.000, a=1.000),
Property(x=0.000, y=0.000, r=0.000, g=0.000, b=0.000, a=0.000),
Property(x=100.000, y=200.000, r=1.000, g=1.000, b=1.000, a=1.000)]
-- Paul

Nov 5 '07 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Gerrit Holl | last post by:
Posted with permission from the author. I have some comments on this PEP, see the (coming) followup to this message. PEP: 321 Title: Date/Time Parsing and Formatting Version: $Revision: 1.3 $...
0
by: bj0011 | last post by:
I am trying to parse an XML file obtained from a public WebService (see below). This file does not seem to be loading into a .NET XmlDocument right (I think it is because of all of the <Item Name=""...
3
by: Zach | last post by:
Say I have a string which is of the format {A, B, C, D} for some variable number of objects. I want a regular expression that will put each of A, B, C, and D into its own separate capture...
4
by: Jim Langston | last post by:
In my program I am accepting messages over the network and parsing them. I find that the function that does this has gotten quite big, and so want to break the if else code into functions. I...
3
by: toton | last post by:
Hi, I have some ascii files, which are having some formatted text. I want to read some section only from the total file. For that what I am doing is indexing the sections (denoted by .START in...
9
by: Paulers | last post by:
Hello, I have a log file that contains many multi-line messages. What is the best approach to take for extracting data out of each message and populating object properties to be stored in an...
2
by: nedelm | last post by:
My problem's with parsing. I have this (arbitrary, from a file) string, lets say: "Directory: /file{File:/filename(/size) }" I would like it to behave similar to LaTeX. I parse it, and then I...
7
by: Eric Wertman | last post by:
I have a set of files with this kind of content (it's dumped from WebSphere): ]
6
by: Paul Wilson | last post by:
Hi all, I'd like to be able to do the following to a python source file programmatically: * Read in a source file * Add/Remove/Edit Classes, methods, functions * Add/Remove/Edit Decorators *...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.