Skip to content

Instantly share code, notes, and snippets.

@xflr6
Last active June 4, 2022 09:33
Show Gist options
  • Save xflr6/5761d36b3db9a9b15970f974de416e59 to your computer and use it in GitHub Desktop.
Save xflr6/5761d36b3db9a9b15970f974de416e59 to your computer and use it in GitHub Desktop.
Make Python regex search/replace functions from sed-like s/old/new/g strings
"""Search/replace func from string roughly like 'sed -r s/old/new/g'."""
from collections.abc import Callable
import functools
def search_replace(cmd: str, *, _cache={}) -> Callable[[str], str]:
"""Return a callable from sed/Perl-style search-replace pattern string.
>>> search_replace('s/ham/spam/g')('ham-eggs-ham')
'spam-eggs-spam'
"""
try:
return _cache[cmd]
except KeyError:
pass
if not (cmd.startswith('s') and len(cmd) >= 6 and cmd.endswith('g')):
raise ValueError(f'{cmd!r}')
sep = cmd[1]
if cmd.count(sep) != 3:
raise ValueError(f'{cmd!r}')
search, _, rest = cmd[2:].partition(sep)
repl, _, rest = rest.partition(sep)
if not search or rest != 'g':
raise ValueError(f'{cmd!r}')
use_mrab = any(v in search for v in ('(?V0)', '(?V1)'))
if use_mrab:
import regex as re
else:
import re
regex = re.compile(search)
result = _cache[cmd] = functools.partial(regex.sub, repl)
result.cmd = cmd
return result
if __name__== '__main__':
import doctest
doctest.testmod(verbose=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment