-1

For example, I have the following string:

s = 'Name: @name, ID: @id'

Now I want to use re.sub() to replace @name and @id. I know that I can use group to catch some string and then use '\g<index>' or r'\index' to use it.

But now I need use it as a dict key, I have this dict:

d = {'id': '20', 'name': 'Jon'}

And I wish I can get this:

s = 'Name: Jon, ID: 20'

Also I tried:

>>> re.sub('@(\w+)', d[r'\1'], s)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
KeyError: '\\1'

>>> re.sub('@(\w+)', d['\g<1>'], s)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
KeyError: '\\g<1>'
>>> 
Remi Guan
  • 21,506
  • 17
  • 64
  • 87

3 Answers3

3

Python provides a string.Template class (see also PEP 292) which can format strings very similar to kind you are working with. By default the string.Template class recognizes $ as the placeholder. If you change it to @ (by subclassing string.Template) then you can perform the substitutions by calling the substitute or safe_substitute method:

import string
class MyTemplate(string.Template):
    delimiter = '@'

content = 'Name: @name, ID: @id'
d = {'id': '20', 'name': 'Jon'}
template = MyTemplate(content)
result = template.safe_substitute(**d)
print(result)

prints

Name: Jon, ID: 20
unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677
  • 1
    Wow, don't know this before :D. But my question is about *use '\g or r'\index' as dict key when use re.sub*. So I can't accept this. But good to know :) – Remi Guan Nov 20 '15 at 03:01
  • Thanks i did not know this cool stuff! Another trick in hat! – Learner Nov 20 '15 at 04:46
1

You need to use the function form for re.sub in this case. For your basic use case, it could be a simple as:

re.sub(r'@(\w+)', lambda m: d[m.group(1)], s)

If the logic is more complicated, a top-level def is the way to go. Basically, you pass a callable instead of a str, per the re.sub docs:

If repl is a function, it is called for every non-overlapping occurrence of pattern. The function takes a single match object argument, and returns the replacement string.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Wow, great! What does `lambda` do here? – Remi Guan Nov 20 '15 at 02:42
  • See [`re.sub` docs](https://docs.python.org/3/library/re.html#re.sub). I'll include a quote in the answer. – ShadowRanger Nov 20 '15 at 02:43
  • Thanks again :P. Will accept answer in 4 mins. – Remi Guan Nov 20 '15 at 02:45
  • 1
    @KevinGuan: BTW, a useful thing to note: `callable`s in Python can have state. This has come up before in [another answer of mine for keeping track of the match number in `re.sub`](https://stackoverflow.com/questions/32980674/how-can-i-know-the-match-index-in-a-regular-expression-subns-repl-function/32980816#32980816). – ShadowRanger Nov 20 '15 at 02:49
0

If formatting your string differently is an option, you can do it this way:

>>> d = {'id': '20', 'name': 'Jon'}
>>> 'Name: {name}, ID: {id}'.format(**d)
'Name: Jon, ID: 20'
rofls
  • 4,993
  • 3
  • 27
  • 37