13

如果字符串包含foo,则替换foobar。否则,追加bar到字符串。如何用一个re.sub(或任何其他函数)调用来编写它?没有条件或其他逻辑。

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"

对于那些好奇的人,在我的应用程序中,我需要替换代码是表驱动的——正则表达式和替换是从数据库中获取的。

4

5 回答 5

9

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)
于 2013-06-24T11:21:38.630 回答
9

试试这个简单的单行,没有正则表达式,没有技巧:

a.replace("foo", "bar") + (a.count("foo") == 0) * "bar"
于 2013-06-24T14:32:58.433 回答
2

你可以这样做

正则表达式:

^(?!.*foo)(.*)$|foo(\b)

或者

foo|^(?!.*foo)(.*)$

用。。。来代替:\1bar

这里工作

于 2013-06-24T11:16:15.913 回答
1

受@zenpoy 启发的两个班轮:

ar =  a.replace("foo", "bar") 
a + 'bar' if a is ar else ar
于 2013-06-24T15:11:23.557 回答
0

你不能用那个奇怪的表弟吗?

re.sub(regex, repl, str) if re.match(regex,str) else str + repl

还是胖表哥?

(str + repl, re.sub(regex, repl, str))[bool(re.match(regex, str))]

两者都不太神秘,尽管与Tim 出色的正则表达式解决方案相比,它们都具有额外的函数调用和逻辑。

于 2013-06-24T21:31:17.147 回答