[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