demand
We frequently need to pre-defined data template is embedded placeholder variables, such as $ name or {{name}} or% (name) s, to facilitate replacement of parameters do.
This requires the use of string format or template engine (such as Jinja2) you will be ready to replace a group of data into the template to the location specified.
Python comes with string formatting there are three general ways:
- The% s or% (name) s
'姓名: %s, 年龄: %d' %('Kevin', 21)
'姓名: %(name)s, 年龄: %(age)d' % {'name':'Kevin', 'age': 21}
- Use .format syntax
'姓名: {}, 年龄: {}'.format('Kevin', 21)
'姓名: {name}, 年龄: {age}'.format(name='Kevin', age=21)
- Use Template and safe_substitute ()
from string import Template
Template('姓名: $name, 年龄: $age').safe_substitute(name='Kevin', age=21)
Specific template rendering engine, such as Jinja2, in addition to rendering the variable supports more features, such as determining if and for loop iterates, filters and the like, using a simple method as follows:
from jinja2 import Template
Template('姓名: {{ name }}, 年龄: {{age}}').render(name='Kevin', age=21)
Yaml file types for rendering embedded variables, or use {%} will be some problems, so we choose to use the $ here as delimiters, sometimes we need to variable substitution in the de-serialization and then, and for a list / dictionary species Alternatively embedded variable, e.g., there is such a list:
s = ['性别: $2 年龄: $3\n$a', '$1', {"say": "$a"}]
We need to replace the data in, which $1
represents the first argument, $a
the representative parameters a
then use the safe_subtitute()
method more trouble, so here is simple implements a
$ variable substitution method
characteristic
- Support
$1
to replace the first parameter, and$a
replace parametersa
- Replace support dictionary / list / Ganso, and nested dictionary / variable list
- It supports the specified delimiter defaults
$
- It supports multi-line text replacement
- When not completely replace, retain the original value, not being given
The principle
Python regular sub Method re library support for custom handlers replacement
re.sub(匹配表达式, 替换值或替换处理函数, 原始文本, re.M) # 使用re.M 支持跨行
Implementation code
import re
import json
def render(origin, *args, delimiter="$", **kwargs): # 支持修改delimiter定界符
patten = r'\{}(?P<var>[\w|_]+)'.format(delimiter)
def repl_func(matched): # 自定义re.sub使用的替换方法
var = matched.group('var')
if var.isdigit(): # 如果是数字, 则从args中替换
index = int(var) - 1
if index < len(args):
return args[index]
else:
return "{}{}".format(delimiter, var) # 无替换参数则返回原值
else:
return kwargs.get(var, None) or "{}{}".format(delimiter, var) # 返回kwargs参数中值 or 原值
if isinstance(origin, str):
return re.sub(patten, repl_func, origin, re.M)
elif isinstance(origin, (dict, list)): # 使用json.dumps转为字符串, 替换,然后重新转为dict/list
return json.loads(re.sub(patten, repl_func, json.dumps(origin), re.M))
else:
if isinstance(origin, tuple):
return tuple(json.loads(re.sub(patten, repl_func, json.dumps(origin), re.M))) # 转换后重新转为tuple
if __name__ == '__main__':
s = ['性别: $2 年龄: $3\n$a', '$1', {"say": "$a"}]
print(render(s, 'kevin', 'male', '20', a="hello, world!"))
Output:
['性别: male 年龄: 20\nhello, world!', 'kevin', {'say': 'hello, world!'}]