[Tutor] find and replace relative to an nearby search string
Paul McGuire
ptmcg at austin.rr.com
Mon Jul 13 12:15:38 CEST 2009
This is a good little pyparsing exercise. Pyparsing makes it easy to define
the structure of a "Write { (<key> <value>)* }" block, and use the names
given to the parsed tokens to easily find the "name" and "file" entries.
from pyparsing import (Literal, Word, alphanums, empty, restOfLine, dictOf)
# make up grammar for expression of a Write block (tiny bit of
# pyparsing magic: define value as "empty + restOfLine" instead
# of just plain restOfLine, because empty will advance the
# parser past any whitespace before starting the capture of
# restOfLine)
WRITE = Literal("Write")
key = Word(alphanums+"_")
value = empty + restOfLine
write_block = WRITE + "{" + dictOf(key,value)("data") + "}"
# SIMPLE VERSION
# if the order of the output key-value pairs is not significant,
# just modify the "file" entry of tokens.data, and iterate
# over tokens.data.items() to create the output
def modify_write1(tokens):
if tokens.data["name"] == "Write1":
tokens.data["file"] = NEW_FILE_VALUE
def tokens_as_string(tokens):
return ("Write {\n" +
"\n".join(" %s %s" % (k,v)
for k,v in tokens.data.items()) + "\n" +
"}")
# SLIGHTLY MORE COMPLICATED VERSION
# if the order of the key-value pairs must be preserved, then
# you must enumerate through tokens.data's underlying list,
# to replace the value associated with "file"
def modify_write1(tokens):
if tokens.data["name"] == "Write1":
for i,(k,v) in enumerate(tokens.data):
if k == "file":
tokens.data[i][1] = NEW_FILE_VALUE
break
def tokens_as_string(tokens):
return ("Write {\n" +
"\n".join(" %s %s" % (k,v)
for k,v in tokens.data) + "\n" +
"}")
# Assign parse actions: for each write_block found, modify the
# file entry if name is "Write1", and then reformat the parsed
# tokens into a string of the right form (since the parser will
# have turned the tokens into a data structure of keys and
# values)
write_block.setParseAction(modify_write1, tokens_as_string)
# define NEW_FILE_VALUE, and use transformString to parse
# through the input text, and process every Write block found
NEW_FILE_VALUE = "/Volumes/raid0/Z353_002_comp_v27.%04d.cin"
print write_block.transformString(text)
If you assign your input test string to the variable 'text', you'll get this
output:
Write {
file /Volumes/raid0/Z353_002_comp_v27.%04d.cin
file_type cin
name Write1
xpos 13762
ypos -364
}
Write {
file /Volumes/raid0/Z353_002_comp_v27.%04d.cin
colorspace linear
raw true
file_type exr
name Write1
selected true
xpos -487
ypos -155
}
Find out more about pyparsing at http://pyparsing.wikispaces.com.
Cheers,
-- Paul
More information about the Tutor
mailing list