7

Imagine a script that receives a string:

http://whatever.org/?title=@Title@&note=@Note@

...and a list of tokens:

['arg:Title=SampleTitle', 'arg:Note=SampleNote']

What is the most Pythonic way to interpolate those tokens into the string, such that, using the above example, the following is produced:

http://whatever.org/?title=SampleTitle&note=SampleNote

I've considered:

  1. Loop through the list and, for every string it contains, split out the token name, and do a regex replace on every instance of @TOKEN_NAME found; and

  2. Use some sort of templating mechanism (similar to what one can do with Ruby's ERB.template).

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
ABach
  • 3,743
  • 5
  • 25
  • 33

1 Answers1

16

To use the Pythonic solution, adopt the str.format specifications for format string syntax:

>>> template = "http://whatever.org/?title={Title}&note={Note}"
>>> template.format(Title="SampleTitle", Note="SampleNote")
'http://whatever.org/?title=SampleTitle&note=SampleNote'

You can also unpack a dictionary of named arguments:

>>> template.format(**{"Title": "SampleTitle", "Note": "SampleNote"})
'http://whatever.org/?title=SampleTitle&note=SampleNote'

If you're stuck with your input format, you could easily switch to something more useful with a regular expression:

>>> import re
>>> s = "http://whatever.org/?title=@Title@&note=@Note@"
>>> re.sub(r"@(\w+?)@", r"{\1}", s)
'http://whatever.org/?title={Title}&note={Note}'

(see regex explanation here)

and process the tokens into a dictionary, too:

>>> tokens = ['arg:Title=SampleTitle', 'arg:Note=SampleNote']
>>> dict(s[4:].split("=") for s in tokens)
{'Note': 'SampleNote', 'Title': 'SampleTitle'}
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Simple and straightforward; thank you. Could you explain what the `**` does in front of the dict in your second example? – ABach Sep 04 '14 at 14:59
  • I have run the above and the `re.sub` statement does not work – Mark Kortink Aug 09 '19 at 18:37
  • @MarkKortink any chance of a little more to go on than *"does not work"*? – jonrsharpe Aug 09 '19 at 18:40
  • When i set `s = "http://whatever.org/?title=@Title@&note=@Note@"` then run `re.sub(r"@(\w+?)@", r"{\1}", s)` i get `s` back unchanged. Is there a regex that can solve the initial problem without having to use `format()`? The reason, i am using jinja which uses `{{ }}` to bracket variables so given format uses `{ }` there is a chance of bugs. – Mark Kortink Aug 09 '19 at 18:45
  • @MarkKortink could not replicate. Are you thinking there would be an in-place transformation? Because strings are immutable. – jonrsharpe Aug 09 '19 at 18:48
  • Ah! That is my error, i assumed the `s` in `re.sub` would be changed. When i do `t = re.sub(r"@(\w+?)@", r"{\1}", s)` it works! Thanks – Mark Kortink Aug 09 '19 at 18:55