Search code examples
python-3.xregexlambdaregex-group

How to replace characters based on variables in a list using regex sub


Is it possible to insert different values in a string based on the same matching pattern by using a list to specify the values to insert? I'm using python 3 and re.sub.

Here is what a mean:

line = "Float: __, string: __"
values = ["float", "string"]

newLine = re.sub('(_+)([.]_+)?',
    (lambda m:
    f'%'
    f'{len(m.group(1))}'
    f'{"." if values == "float" else ""}'
    f'{(len(m.group(2) or ".")-1) if values == "float" else ""}'
    f'{"f" if values == "float" else "s"}'),
    line)

print(newLine)                                                

Expected result:

Float: %2.0f, string: %2s

Actual result:

Float: %2s, string: %2s

Is it posssible to loop through the values list in order to get the correct result (this is not working and I get a TypeError)? Something like:

newLine = re.sub('(_+)([.]_+)?',
    ((lambda m:
    f'%'
    f'{len(m.group(1))}'
    f'{"." if v == "float" else ""}'
    f'{(len(m.group(2) or ".")-1) if v == "float" else ""}'
    f'{"f" if v == "float" else "s"}') for v in values),
    line)

Edit 1 The values list and the amount of matching patterns are always of same length.


Solution

  • You cannot loop like this inside the repl argument, but you can define a counter and pass it to the repl function:

    import re
    
    line = "Float: __, string: __"
    values = ["float", "string"]
    obj = lambda:None
    obj.i = -1
    
    def repl(m, count, values):
        count.i += 1
        return f'%{len(m.group(1))}{"." if values[count.i] == "float" else ""}{(len(m.group(2) or ".")-1) if values[count.i] == "float" else ""}{"f" if values[count.i] == "float" else "s"}'
    
    newLine = re.sub(r'(_+)(\._+)?',
        lambda m: repl(m, obj, values),
        line)
    
    print(newLine)      
    ## => Float: %2.0f, string: %2s
    

    See the Python demo.

    Here, an obj object is declared, and its i property is initialized with -1. Then, inside the repl function, its value is incremented and used as the index of the values list.

    Note that this approach works only if the number of matches equals the amount of items in the values list.