zoukankan      html  css  js  c++  java
  • 如何在模板中将$变量替换为变量值

    需求

    经常我们在定义数据模板是需要预先埋设一些变量占位符, 如$name或{{name}}或%(name)s, 来便于做参数化替换.
    这便需要使用字符串格式化,或者模板引擎(如Jinja2)来将你准备好的一批数据替换到模板指定的位置中去.
    Python自带的字符串格式化方式一般有3种:

    1. 使用%s或%(name)s
    '姓名: %s, 年龄: %d' %('Kevin', 21) 
    '姓名: %(name)s, 年龄: %(age)d' % {'name':'Kevin', 'age': 21} 
    
    1. 使用 .format语法
    '姓名: {}, 年龄: {}'.format('Kevin', 21) 
    '姓名: {name}, 年龄: {age}'.format(name='Kevin', age=21) 
    
    1. 使用Template及safe_substitute()
    from string import Template
    Template('姓名: $name, 年龄: $age').safe_substitute(name='Kevin', age=21)
    

    专用的模板渲染引擎, 如Jinja2, 则除渲染变量外还支持更丰富的功能, 如if判断和for循环遍历, 以及过滤器等, 简单使用方法如下:

    from jinja2 import Template
    Template('姓名: {{ name }}, 年龄: {{age}}').render(name='Kevin', age=21)
    

    对于yaml文件种埋设变量的渲染, 使用%或{}会有些问题, 所以我们这里选择使用$作为定界符, 有时候我们需要在反序列化后再进行变量替换, 及对列表/字典种的埋设变量进行替换, 如,有这样一个列表:

     s = ['性别: $2  年龄: $3
    $a', '$1', {"say": "$a"}]
    

    我们需要将数据替换进去, 其中, $1代表第1个参数, $a代表参数a
    这时使用与safe_subtitute()方法就比较麻烦, 于是这里简单实现了一个
    $变量替换方法

    特性

    1. 支持$1替换第1个参数, 及$a替换参数a
    2. 支持字典/列表/元祖, 以及嵌套字典/列表中变量的替换
    3. 支持指定定界符, 默认为$
    4. 支持多行文本替换
    5. 不完全替换时, 保留原值, 不会报错

    实现原理

    Python正则 re库中的sub方法支持自定义替换处理函数

    re.sub(匹配表达式, 替换值或替换处理函数, 原始文本, re.M)   # 使用re.M 支持跨行
    

    实现代码

    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
    $a', '$1', {"say": "$a"}]
        print(render(s, 'kevin', 'male', '20', a="hello, world!"))
    
    

    输出结果:

    
    ['性别: male  年龄: 20
    hello, world!', 'kevin', {'say': 'hello, world!'}]
    
    
  • 相关阅读:
    CF1454F Array Partition
    leetcode1883 准时抵达会议现场的最小跳过休息次数
    leetcode1871 跳跃游戏 VII
    leetcode1872 石子游戏VIII
    CF1355C Count Triangles
    CF1245D Shichikuji and Power Grid
    CF1368C Even Picture
    CF1368D AND, OR and square sum
    CF1395C Boboniu and Bit Operations
    SpringBoot和开发热部署
  • 原文地址:https://www.cnblogs.com/superhin/p/11454931.html
Copyright © 2011-2022 走看看