SimpleTemplate模板引擎开发
模板引擎相信大家是经常使用的,但是实现原理估计没多少人知道(你要是说不就是replace嘛,那我也无话说了...)。
先来看看这个SimpleTemplate想实现的是什么功能吧:
- 是个C#端的模板引擎
- 模板中能放普通变量(i, j, index, username这种直接了当的变量名)
- 模板中能放复合变量(user.FirstName, user.LastName这种有对象前缀的变量)
最终客户端代码通过下面的方式进行调用:
static void Main(string[] args){string template = @" your name: @{name} your age: @{age} ";Dictionary<string, object> ctx = new Dictionary<string, object>();ctx["name"] = "McKay";ctx["age"] = "你猜";Console.WriteLine(STParser.GenerateStringView(template, ctx));Console.ReadKey();}
大家看出来了,重点就在@{xxxx}上
大家也先别喷我,说用正则、replace就搞定了,看后面先,小心喷了后悔。
我选择用antlr来做这个模板引擎,因为虽然现在看上去这个模板引擎很简单,但是不代表以后不扩展啊,以后还要加入if/else/for这种通用编程语法的,所以为了扩展性,就用语法解析器了。
知道yacc/flex的也可以去看看,只不过没有C#插件,而antlr正好有这插件,就用了。
下面我们先来写文法规则:
parse:expression*;expression: stringtext| simple_variable| complex_variable;
parse
规则代表开始规则,这个名称可以自己起名,只要是小写就行。
内容只有一行,expression*,代表0个或者无限个expression规则
expression
看清,第一个是冒号“:”,后续的是或者号“|”,最后是封号";"
代表expression可以是三种规则中的一种:stringtext、simple_variable、complex_variable,代表普通的字符串文本、简单变量、复合变量规则
先来看看普通文本字符串的定义
stringtext: placeholderChar (placeholderChar)*| newlines;placeholderChar: CHAR| ':'| SPACE| NUMBER| DOT| '\''| '"'| '<'| '>'| '_'| '+'| '-'| '*'| '/';newlines:NEWLINE NEWLINE*;NEWLINE:'\r'? '\n'; NUMBER: '0'..'9'; CHAR: 'a'..'z'|'A'..'Z'; SPACE:' '; DOT:'.';
stringtext
二选一的规则
第一行代表至少一个占位字符的字符串(后面用了*号,就代表字符数不限)
newlines,看后面的定义也是用了*号,代表一个回车,或者多个回车的规则匹配
占位符,大家看placeholderChar规则,就知道允许的占位符是哪些字符了
注意:大写的规则其实不是规则,而是token
再来看看简单变量规则的定义
simple_variable:V_START simple_variable_inner V_END;simple_variable_inner:identity;identity:(UNDERLINE|CHAR) (UNDERLINE|CHAR|NUMBER)*;V_START:'@{'; V_END:'}'; NUMBER: '0'..'9'; CHAR: 'a'..'z'|'A'..'Z'; UNDERLINE: '_';
simple_variable
定义了一个V_START的TOKEN为开头,也定义了必须以V_END为结尾,字符分别是 @{和},呵呵,中间就是那个变量名了
这个变量名其实就是identity规则的定义,是说第一个字符必须以下划线或英文字母开头,后续字符可有可无,有的话必须是下划线、英文字母、数字
再看看复合变量的规则
complex_variable:V_START complex_variable_inner V_END; complex_variable_inner:identity DOT identity;identity:(UNDERLINE|CHAR) (UNDERLINE|CHAR|NUMBER)*;DOT:'.';
说说这里的complex_variable_inner规则
由于是要匹配obj.property格式,因此用了个点号DOT,obj和property的规则匹配其实就是identity的规则匹配
我们看看上面规则的效果,antlr解析树:
还是比较帅的
下面的问题是,怎么运用到C#项目中了
怎么运用到C#项目中
首先,新建一个项目,然后在NuGet中搜索"antlr" ,找到antlr4,然后安装
然后新建一个任意文件,新建后重命名为g4文件,比如SimpleTemplate.g4,接着还要设置下这个g4文件的生成方式,如下图
这样,当我们生成时,antlr就会根据g4文件的规则定义生成对应的C#代码了。
然后再说说g4文件的内容是怎么拷贝过来(原先的解析树是在eclipse中才能看的,所以原先的g4定义都在那边做的)
首先,上方的grammar xxxxx;这里的xxxxx必须要和文件名称一致。
其次,compileUnit后面的那个规则,必须存在,代表默认规则
再其次,如果编译时总是报错(但是eclipse中是正常的),这时要修改下vs环境下的g4文件的编码,如下:
还得把eclipse中的g4文件内容拷贝到新的g4文件中,别忘了。
接下来就要进入C#编码层面了,呵呵,是不是有点不耐烦了,`(*∩_∩*)′
挂钩函数就那么一个,很简单,基本就是拷贝:
public static class STParser{public static string GenerateStringView(string template, Dictionary<string, object> variables){Antlr4.Runtime.AntlrInputStream input = new Antlr4.Runtime.AntlrInputStream(template);TemplateLexer lexer = new TemplateLexer(input);Antlr4.Runtime.UnbufferedTokenStream tokens = new Antlr4.Runtime.UnbufferedTokenStream(lexer);TemplateParser parser = new TemplateParser(tokens);var tree = parser.parse();SimpleTemplateVisitor visitor = new SimpleTemplateVisitor(variables);string result=visitor.Visit(tree);return result;}}
template是传进来的模板文本
variables是传进来的变量集合
这段代码中都是antlr引擎自动生成的类,除了SimpleTemplateVisitor是自定义的(不然咋替换字符串啊)
来看看这个类吧,里面都是VisitXXXX规则的函数重载,需要的自定义逻辑都在里面改写
class SimpleTemplateVisitor:g4.TemplateBaseVisitor<string>{private Dictionary<string, object> ctx;public SimpleTemplateVisitor(Dictionary<string, object> ctx){this.ctx = ctx;}public override string VisitParse(g4.TemplateParser.ParseContext context){StringBuilder sb = new StringBuilder();foreach(var exp in context.expression())sb.Append(VisitExpression(exp));return sb.ToString();}public override string VisitNewlines(g4.TemplateParser.NewlinesContext context){return context.GetText();}public override string VisitStringtext(g4.TemplateParser.StringtextContext context){return context.GetText();}public override string VisitSimple_variable(g4.TemplateParser.Simple_variableContext context){return VisitSimple_variable_inner(context.simple_variable_inner());}public override string VisitComplex_variable(g4.TemplateParser.Complex_variableContext context){return VisitComplex_variable_inner(context.complex_variable_inner());}public override string VisitSimple_variable_inner(g4.TemplateParser.Simple_variable_innerContext context){string var_name = context.identity().GetText();if (!ctx.ContainsKey(var_name))throw new NullReferenceException(var_name);return Convert.ToString(ctx[var_name]);}public override string VisitComplex_variable_inner(g4.TemplateParser.Complex_variable_innerContext context){string var_name = context.identity()[0].GetText();if (!ctx.ContainsKey(var_name))throw new NullReferenceException(var_name);string propertyName = context.identity()[1].GetText();object obj = ctx[var_name];Type t = obj.GetType();PropertyInfo propertyInfo = t.GetProperty(propertyName);var value = propertyInfo.GetValue(obj, null);string string_value = Convert.ToString(value);return string_value;}}
构造函数中传入的ctx是我们要替换的变量集合
光看这些函数是会晕的,你得结合eclipse中的解析树层次图来同时看,要清楚的知道上下关系,然后再套上面这个visit类才能看懂,呵呵,慢慢折腾看吧。
此处等待数周。。。
上面这个只是替换变量的没意思,我们再做个有循环的,比如:
your name: @{user.name} your age: @{user.age}1 23@{repeat 5} testing @{end repeat} --------------------- @{repeat count} testing @{end repeat}
看,支持了循环repeat语法
repeat后面可以支持固定的数字,也可以支持简单变量,也可以支持复合变量,大家应该能在脑子里画出规则形状来吧。
有兴趣深入的同学可以自己试下实现if/else语法。
代码已经上传到github上了,url: https://github.com/daibinhua888/SimpleTemplate/
转载于:https://www.cnblogs.com/aarond/p/4856402.html
SimpleTemplate模板引擎开发相关推荐
- 由浅入深:自己动手开发模板引擎——解释型模板引擎
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(四)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(三)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(二)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——置换型模板引擎(一)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 由浅入深:自己动手开发模板引擎——解释型模板引擎(二)
受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...
- 写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)
前些时间在看创智博客韩顺平的Smarty模板引擎教程,再结合自己跟李炎恢第二季开发中CMS系统写的tpl模板引擎.今天就写一个迷你版的Smarty引擎,虽然说我并没有深入分析过Smarty的源码,但是 ...
- beetl模板使用场景_Java 模板引擎 Beetl 2.0 发布
Java开源模板引擎 Velocity Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由 ...
- thymeleaf 模板引擎
thymeleaf 简介 SpringBoot默认不支持JSP,因为jsp相对于一些模板引擎,性能都比较低,官方推荐使用thymeleaf. Thymeleaf是一个Java模板引擎开发库,可 ...
最新文章
- 配置发布和禁用复制功能时提示 分发服务器未正确安装。
- vc2005运行库彻底卸载_解决不安装VC运行库(VC2005,VC2008),程序运行出错的方法...
- 快速排序(quick sort) C++
- html页面展示Json样式
- 八十七、Python | 十大排序算法系列(上篇)
- C++包含头文件几种方式
- 特殊类型窗体制作: 用C#实现启动欢迎界面
- Linux 之父怒删工程师提交的补丁,称“太蠢了”网友:怼得好!
- Notification通知
- 1.1确定分数与浮点数值之间的近似相等性。
- 少儿是先学计算机 还是学机器人,孩子学机器人好还是少儿编程好
- STM32串口调试一直打印 00 00
- F(x) - NU ABO 韩中(繁)ass字幕
- linux文件授权用户创建
- scala linearization
- 处理复旦大学中文文分类数据集
- 哪几款车型?适合狮子座的车友?
- 44道Redis面试题,含参考答案!
- 在微软Azure的服务器上创建Windows虚拟机的教程
- Unity 电脑CPU 显卡查询 存储空间查询
热门文章
- 软件架构最佳实践和案例分析
- 买卖股票的最佳时机|||
- gin构建包含模板的二进制文件
- linux命令tcpdump
- STM32实现IAP功能之一
- s3c6140 UART驱动设计
- NAND Flash和NOR Flash的区别
- 前端一HTML:十九继承的特殊性
- Android 系统镜像: boot.img kernel.img ramdisk.img system.img userdata.img cache.img recovery.img
- 不用vim-airline/lightline.vim, 如何使用纯手工制作一个漂亮的 vim 状态栏