bottle.py中的SimpleTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import re
 
class SimpleTemplate(object):
 
    re_block = re.compile(r'^\s*%\s*((if|elif|else|try|except|finally|for|while|with).*:)\s*$')
    re_end   = re.compile(r'^\s*%\s*end(.*?)\s*$')
    re_code  = re.compile(r'^\s*%\s*(.*?)\s*$')
    re_inc   = re.compile(r'\{\{(.*?)\}\}')
 
    def __init__(self, template):
        self.code = "\n".join(self.compile(template))
        self.co = compile(self.code, '<string>', 'exec')
 
    def render(self, **args):
        ''' Returns the rendered template using keyword arguments as local variables. '''
        args['stdout'] = []
        args['__builtins__'] = __builtins__
        eval(self.co, {}, args) # 执行Python代码
        return ''.join(args['stdout'])
 
    def compile(self, template):
        '''
        将模板转换为可执行的Python代码
        '''
        def code_str(level, line, value):   # 可直接输出的字符串
            value = "".join(value)
            value = value.replace("'","\'").replace('\\','\\\\')
            return '    '*level + "stdout.append(r'''%s''')" % value
        def code_print(level, line, value): # {{...}}中的内容,需要执行代码后取得字符串再输出
            return '    '*level + "stdout.append(str(%s)) # Line: %d" % (value.strip(), line)
        def code_raw(level, line, value):   # 以%开头,需要作为代码执行
            return '    '*level + value.strip() + ' # Line: %d' % line
 
        level = 0       # 缩进深度
        ln = 0          # 行号(无具体作用,方便定位问题)
        sbuffer = []    # 模板中的普通字符串
        for line in template.splitlines(True):
            ln += 1
            # Line with block starting code
            m = self.re_block.match(line)
            if m:
                if sbuffer:
                    yield code_str(level, ln, sbuffer)
                    sbuffer = []
                if m.group(2).strip().lower() in ('elif','else','except','finally'):
                    if level == 0:
                        raise TemplateError('Unexpected end of block in line %d' % ln)
                    level -= 1
                yield code_raw(level, ln, m.group(1).strip())
                level += 1
                continue
            # Line with % end marker
            m = self.re_end.match(line)
            if m:
                if sbuffer:
                    yield code_str(level, ln, sbuffer)
                    sbuffer = []
                if level == 0:
                    raise TemplateError('Unexpected end of block in line %d' % ln)
                level -= 1
                continue
            # Line with % marker
            m = self.re_code.match(line)
            if m:
                yield code_raw(level, ln, m.group(1).strip())
                continue
            # Line with inline code
            lasts = 0
            for m in self.re_inc.finditer(line):
                sbuffer.append(line[lasts:m.start(0)])
                yield code_str(level, ln, sbuffer)
                sbuffer = []
                lasts = m.end(0)
                yield code_print(level, ln, m.group(1))
            if lasts:
                sbuffer.append(line[lasts:])
                continue
            # Stupid line
            sbuffer.append(line)
 
        if sbuffer:
            yield code_str(level, ln, sbuffer)
 
 
if __name__ == "__main__":
    # 简单替换
    t1 = SimpleTemplate('Hello {{name}}!')
    print t1.render(name='<b>World</b>')
    # 嵌入python语句(必须返回str)
    t2 = SimpleTemplate('Hello {{name.title() if name else "stranger"}}!')
    print t2.render(name=None)
    print t2.render(name="tuzkee")
    # %执行Python语句
    tmp3="""
%if name:
  Hi <b>{{name}}</b>
%else:
  <i>Hello stranger</i>
%end"""
    t3 = SimpleTemplate(tmp3)
    print t3.render(name=None)
    tmp4="""
%for i in range(3):
%for j in range(3):
    {{"%s:%s"%(i,j)}}
%end
%end"""
    t4 = SimpleTemplate(tmp4)
    print t4.render()

 

posted @   鸪斑兔  阅读(247)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示