krayzk
krayzk

Reputation: 927

Pythonically creating a string-modifying lambda function dynamically based off of input recieved

I have a web form that accepts user input for string modifications to be applied to information being passed via a given column in a csv. Because I am attempting to use existing architecture I am applying these modifications to lambda functions. For most of the mods it is fairly straight forward, but for my replace modification I would like to do this dynamically, for example a string I might receive from my form might be:

('you', 'me' / 'this', 'that' / 'do', "don't")

the lambda equivalent I would like to create for passing with this data would be:

func = lambda v: str(v).replace('you', 'me').replace('this', 'that').replace('do', "don't")

I can easily do this by limiting the amount of replaces that can be done and then counting the delimiters ('/' in this case) and creating them individually using if statements and such.
I hate this idea for 2 reasons:

  1. I am effectively limiting my users modification capabilities by putting limits on how many modifications they are allowed to do on a given string
  2. it does not feel pythonic.

I would prefer an approach like this:

func = lambda v: str(v)
for mod in modstring.split(' / '):
    func = func + .replace(mod.split(', ')[0], mod.split(', ')[1])

but I highly doubt such functionality exists... I figure this question is a long-shot but it was worth a try.

Upvotes: 0

Views: 1297

Answers (3)

Hugh Bothwell
Hugh Bothwell

Reputation: 56674

import re

# I am going to assume that your form input is literally of the form
# """('you', 'me' / 'this', 'that' / 'do', "don't")"""
# so this parses it into
# [("you", "me"), ("this", "that"), ("do", "don't")]
def parse_form_string(s, reg=re.compile("(['\"])(.*?)(\\1)")):
    words = [qw[1] for qw in reg.findall(s)]
    return zip(words[::2], words[1::2])

# we use the input-string to build a function
# which will perform the replacements
def my_replace_fn(form_string):
    pairs = parse_form_string(form_string)
    def fn(s):
        for a,b in pairs:
            s = s.replace(a, b)
        return s
    return fn

# then we can use it like
inp = """("cat", 'dog' / "mouse", "flea" )"""
my_fn = my_replace_fn(inp)

my_fn("my cat has a mouse")   # => "my dog has a flea"

Upvotes: 2

nneonneo
nneonneo

Reputation: 179552

lambdas and regular functions are interchangeable. So, I'd write this as a function returning a function:

def make_replacer(s):
    mods = [mod.split(', ') for mod in s.split(' / ')]
    def replacer(v):
        v = str(v)
        for mod in mods:
            v = v.replace(mod[0], mod[1])
        return v
    return replacer

Example use:

>>> f1 = make_replacer('foo, bar / moo, car')
>>> f2 = make_replacer('foo, dar / moo, ear')
>>> f1('foo$$moo')
'bar$$car'
>>> f2('foo$$moo')
'dar$$ear'

Upvotes: 2

Travis D.
Travis D.

Reputation: 342

Consider this:

parse_replace = lambda i: i.split(', ') # 'one, two' => [ 'one', 'two' ]

f = lambda v, inputstring: reduce( lambda a,b: a.replace(*parse_replace(b)), v.split(' / '), inputstring )

# So: f('one, derp / three, four', 'onetwothree') # ==> 'derptwofour'

Note: This assumes your input string is actually formatted like: 'one, two / three, four'.

Upvotes: 1

Related Questions