Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to turn %s into {0}, {1} ... less clunky?

I have to take a string containing placeholders for later substitution, like:

"A %s B %s"

And turn that into:

"A {0} B {1}"

I came up with:

def _fix_substitution_parms(raw_message):
  rv = raw_message
  counter = 0
  while '%s' in rv:
    rv = rv.replace('%s', '{' + str(counter) + '}', 1)
    counter = counter + 1
return rv

That works, but it feels super clunky, and not at all "idiomatic" python.

How would a well, idiomatic python solution look like?

Updates for clarification:

  • the resulting strings aren't used within python. I do need the counter numbers in there! (so {} isn't good enough)!
  • I only need to care about %s strings, as the messages are guaranteed to only use %s (no %i %f whatsoever)
like image 495
GhostCat Avatar asked Oct 14 '19 12:10

GhostCat


3 Answers

Use re.sub with a lambda function for reapplying the substitution once for each element, and itertools.count for getting numbers sequentially:

import itertools
import re

s = "A %s B %s"

counter = itertools.count()
result = re.sub('%s', lambda x: f'{{{next(counter)}}}', s)
print(result)  # 'A {0} B {1}'

Remember to wrap this in a function to perform this operation more than once, since you'll need to refresh itertools.count.

like image 77
jfaccioni Avatar answered Nov 02 '22 03:11

jfaccioni


I would do what Reznik originally suggested and then call .format on that:

def _fix_substitution_parms(raw_message: str) -> str:
    num_to_replace = raw_message.count("%s")
    python_format_string_message = raw_message.replace("%s", "{{{}}}")
    final_message = python_format_string_message.format(*range(num_to_replace))
    return final_message
like image 24
Dan Avatar answered Nov 02 '22 03:11

Dan


I think that shoudl work

rv.replace('%s','{{{}}}').format(*range(rv.count('%s')))

like image 22
Reznik Avatar answered Nov 02 '22 05:11

Reznik