Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace x with y or append y if no x

Tags:

python

regex

If a string contains foo, replace foo with bar. Otherwise, append bar to the string. How to write this with one single re.sub (or any other function) call? No conditions or other logic.

import re

regex = "????"
repl  = "????" 

assert re.sub(regex, repl, "a foo b")       == "a bar b"
assert re.sub(regex, repl, "a foo b foo c") == "a bar b bar c"
assert re.sub(regex, repl, "afoob")         == "abarb"
assert re.sub(regex, repl, "spam ... ham")  == "spam ... hambar"
assert re.sub(regex, repl, "spam")          == "spambar"
assert re.sub(regex, repl, "")              == "bar"

For those curious, in my application I need the replacement code to be table-driven - regexes and replacements are taken from the database.

like image 270
georg Avatar asked Jun 24 '13 11:06

georg


2 Answers

This is tricky. In Python, replacement text backreferences to groups that haven't participated in the match are an error, so I had to build quite a convoluted construction using lookahead assertions, but it seems to pass all the test cases:

result = re.sub("""(?sx)
    (              # Either match and capture in group 1:
     ^             # A match beginning at the start of the string
     (?:(?!foo).)* # with all characters in the string unless foo intervenes
     $             # until the end of the string.
    |              # OR
     (?=foo)       # The empty string right before "foo"
    )              # End of capturing group 1
    (?:foo)?       # Match foo if it's there, but don't capture it.""", 
                     r"\1bar", subject)
like image 125
Tim Pietzcker Avatar answered Sep 28 '22 01:09

Tim Pietzcker


Try this simple one-liner, no regexp, no tricks:

a.replace("foo", "bar") + (a.count("foo") == 0) * "bar"
like image 28
zenpoy Avatar answered Sep 28 '22 01:09

zenpoy