1

The following works:

from string import Template
d = { "test" : "1234" }
t = "This is a test: ${test}"
s = Template(t).safe_substitute(d)
print(s) 

Output:

This is a test: 1234

However, what if I only want This is a test: 12 in the output? Can I somehow combine template string substitution and slicing?

If I change t to "This is a test: ${test}[:2]" it prints:

This is a test: 1234[:2]

And if I change t to "This is a test: ${test[:2]}" it prints:

This is a test: ${test[:2]}

I'm not sure if I can use str.format, since both the string and the dict are loaded dynamically from files.

I cannot use f-strings, because I need to be Python 3.4 compatible.

Mike Scotty
  • 10,530
  • 5
  • 38
  • 50
  • u can try `Template(t).safe_substitute(d)[:-2]` – Shijith Jul 23 '19 at 09:35
  • possible duplicate of https://stackoverflow.com/questions/14072810/slicing-strings-in-str-format – Luv Jul 23 '19 at 09:36
  • 2
    @Shijith True for this specific case, but it will not work if the substitution has to be done somewhere in the middle of the template string. – Mike Scotty Jul 23 '19 at 09:37
  • @MikeScotty How about a duplicate dictionary. `s=Template(t).safe_substitute({key:val[:2] for key,val in d.items()})` ? Although, not much efficient when the no of buckets are more and doing it everytime. – BarathVutukuri Jul 23 '19 at 09:43
  • It should be possible to subclass `string.Template` and make this work. Maybe use `ast.parse` to parse the slice syntax. But I suspect it's less work to upgrade to a version of python that support f-strings instead. 3.4 has reached end of life. – Håken Lid Jul 23 '19 at 09:52

1 Answers1

2

I am pretty sure you can't do it directly in the Template string. One solution that you could try is to effectively do any string formatting before you template, by using a formatting dictionary and then combining them.

from string import Template
d = { "test" : "1234" }
format_dict = {"test": "{:2.2}"}
t = "This is a test: ${test}"
s = Template(t).safe_substitute({k: v.format(d[k]) for k, v in format_dict.items()})
print(s) 

Output:

This is a test: 12

EDIT: Per @Jon Clements comment you can make this work so you only need specify formatting for some values.

from string import Template
d = { "test" : "1234" }
format_dict = {"test": "{:2.2}"}
t = "This is a test: ${test}"
formatted = {k: str.format(format_dict.get(k, '{}'), v) 
             for k, v in d.items()}
s = Template(t).safe_substitute(formatted)
print(s)
PyPingu
  • 1,697
  • 1
  • 8
  • 21
  • 1
    I like this idea... it does seem to require you to specify a format for every possible item though... you can re-work it to be something like: `{k: format(v, format_dict.get(k, '')) for k, v in d.iteritems()}` instead... that means you'll get all items available from `d` with their default `str()` formatting, unless you specify otherwise, instead of only items that exist in `format_dict`... – Jon Clements Jul 23 '19 at 10:19
  • Nice work-around. It requires you to have a separate dict for formatting, but I can live with that. – Mike Scotty Jul 23 '19 at 11:01