stgatilov
stgatilov

Reputation: 5533

re.sub convert template to function

I'm using re.sub to replace ARB-style names with GLSL-style ones in a string. Now I want to additionally store all converted matches into a set of strings. Can I do this while still using the "template" syntax of re.sub?

Here is the code:

# set of replacement rules
expl_table = [
    (r'program.env\[(\d+)\]'  , r'program_env_\1'),
    (r'program.local\[(\d+)\]', r'program_local_\1'),
]
for props in expl_table:
    (re_from, re_to) = props
    # arg = re.sub(re_from, re_to, arg)       # simple and good
    def replace_func(m):
        result = ??repl_template??(m, re_to)  # where can I find it?
        declarations.append(result)           # want to save all replacements
        return result
    arg = re.sub(re_from, replace_func, arg)

I have found something like _subx in source code, but it seems to be closed. It seems that I have to implement it myself, as stupid as it sounds.

Upvotes: 3

Views: 141

Answers (1)

Jan
Jan

Reputation: 43169

You could change your string while iterating over it with re.finditer():

# set of replacement rules
expl_table = [
    (r'program.env\[(\d+)\]'  , r'program_env_dsdsds\1'),
    (r'program.local\[(\d+)\]', r'program_local_\1'),
]

declarations = []
for props in expl_table:
    (re_from, re_to) = props

    offset = 0
    for m in re.finditer(re_from, string):
        sub = m.expand(re_to)

        string = string[:m.start()+offset] + sub + string[m.end()+offset:]
        offset = max(map(len, [sub, m.group(0)])) - min(map(len, [sub, m.group(0)]))
        declarations.append(sub)

print(string)

Alternatively, you could "upgrade" a lambda function within the same scope. Usually, it's not allowed to use multiple statements within a lambda function but a list comprehension somewhat bypasses that constraint:

for props in expl_table:
    (re_from, re_to) = props
    string = re.sub(re_from,
                lambda m: [
                           (result, declarations.append(result)) 
                           for result in [m.expand(re_to)]
                          ][0][0],
                 string)

print(string)
print(declarations)

Upvotes: 1

Related Questions