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() |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?