How do I, with one regex, transform:

logger.info(f"Foo {alpha}")
logger.info(f"Foo {alpha} bar {beta}")
logger.info(f"Foo {alpha} bar {beta} baz {gamma}")


logger.info("Foo %s", alpha)
logger.info(f"Foo %s bar %s", alpha, beta)
logger.info(f"Foo %s bar %s baz %s", alpha, beta, gamma)


Idiomatically, log strings in Python should be written using "percent formatting", similar to formatting strings in c using printf, e.g.

o = { "lemurian": "lemurs" }
p = "are leaping"
logger.info("Something something %s %s", o, p)

Which outputs "Something something { "lemurian": "lemurs" } are leaping".

However, I have written lots of log messages with directly interpolated values, e.g.

o = { "lemurian": "lemurs" }
p = "are leaping"
logger.info("Something something {o} {p}")

Which outputs the same as above. I can change things by hand, but it's a pain. :D

  • 1
    If your python supports f-strings, it's a vastly easier problem to simply add f to the beginning of strings (though still not error-free)
    – D. Ben Knoble
    Nov 10 '21 at 18:25
  • 1
    I suspect this is related and may help: vi.stackexchange.com/questions/30981/…
    – D. Ben Knoble
    Nov 10 '21 at 18:26
  • 1
    @D.BenKnoble I'm trying to get rid of the f-strings. :)
    – Kit Peters
    Nov 10 '21 at 18:28
  • 1
    Yeah, on second thought, that post may not be too helpful.
    – D. Ben Knoble
    Nov 10 '21 at 18:33
  • 1
    Why "one regex" (which I assume means "one substitution")? If this is just about getting the job done, I should think that one macro, one command (or series of commands) or even one function would be acceptable, no? Basically, "one operation"...
    – B Layer
    Nov 10 '21 at 18:43

Here's a macro that does the transformation for a single {} that uses surround.vim:

let @q = "0f{ca}%s\<esc>f)i, \<esc>pds{"

(You can also record this by hand.)

Now, unfortunately, running this once for each {} group is harder. You could do it manually, of course, with /{Entern@qn@@n@@…. You can get part of the way to automation with

:global/logger.info(f/normal! @q

which does a single step, and then you can iterate that with @: until there are no more brace-groups.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.