由浅入深:自己动手开发模板引擎——置换型模板引擎(一)

编辑器加载中... 转自:http://www.cnblogs.com/ymind/archive/2012/03/31/progressively-develop-templateEngine-yourself-replacement-type-1.html 受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术。本系列文章将会带您由浅入深的全面认识模板引擎的概念、设计、分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎。关于模板引擎的概念,我去年在百度百科上录入了自己的解释(请参考:模板引擎)。老陈曾经自己开发了一套网鸟Asp.Net模板引擎,虽然我自己并不乐意去推广它,但这已经无法阻挡群友的喜爱了! 很显然,置换型模板引擎说的就是替换式模板引擎。它的工作原理是查找和替换字符串,但这个字符串的替换过程又分为直接查找替换和按流替代输出两种。直接查找替换实现简单,但存在一定的性能障碍,而按流替代的方式性能更好一点,但理解起来却没那么容易。今天我们就专门来讨论讨论置换型模板引擎的关键技术和实现。 概念 按照不同的置换方案,置换型模板引擎分为查找替换式和按流替代式两种。查找替换式又分为字符串替换和正则替换两种。 大家应该都很理解查找替换式模板引擎的含义了,它就是把定义好的标记替换为我们需要的内容即可。而按流替代式虽然在结果上也是将我们指定的标记“替换”为了实际内容,但它内部并没有用到Replace()这种方式,而是在遇到标记的时候直接写出对应的内容,它实际上没有所谓的替换操作,因此性能会好一些。 查找替换式 查找替换这个词大家已经是再也熟悉不过了,我们几乎每天都要编写一次或几次Replace()代码。而查找替换也是构建模板引擎的最基本的思想,任何模板引擎的机制归根结底都还是查找替换。假设我们有如下模板代码和业务数据: 1 /// 2 /// 模板文本。 3 /// 4 private const string _TEMPLATE_STRING = @"{title}
"; 5 6 /// 7 /// 业务数据。 8 /// 9 private Dictionary _newsItems = new Dictionary { 10 {"http://news.qq.com/a/20120330/001077.htm", "7名塔利班人员乔装女性 欲打入北约内部被捕"}, 11 {"http://news.qq.com/a/20120330/001409.htm", "乌克兰遭轮奸焚烧少女伤重不治离世"}, 12 {"http://news.qq.com/a/20120330/001288.htm", "国际空间站宇航员拍到北马里亚纳一火山喷发"}, 13 {"http://news.qq.com/a/20120330/001535.htm", "土耳其同性恋男子可免除兵役 须提供确凿证据"}, 14 {"http://news.qq.com/a/20120330/000874.htm", "英首相卡梅伦公布宴客名单 否认为筹款聚餐"}, 15 {"http://news.qq.com/a/20120329/001774.htm", "孩子飞行途中胡闹不守秩序 全家四口被赶下飞机"}, 16 {"http://news.qq.com/a/20120329/001771.htm", "男子上厕所时抽水马桶突然爆炸 大腿和背部受伤"}, 17 {"http://news.qq.com/a/20120329/001685.htm", "美国总统奥巴马有意与林书豪切磋球艺"}, 18 {"http://news.qq.com/a/20120329/001696.htm", "法国家长与教师联合抵制家庭作业 称加剧不平等"}, 19 {"http://news.qq.com/a/20120329/001650.htm", "印尼政府称超短裙“色情” 欲对其颁布禁令"} 20 }; 复制代码 字符串替换 要使用如上的业务数据生成一个新闻列表,那么做法不外乎如下的代码实现了: 1 /// 2 /// 最简单的模板引擎。 3 /// 4 [Test] 5 public void StringReplace() 6 { 7 var html = new StringBuilder(); 8 9 foreach (var newsItem in this._newsItems) 10 { 11 // 查找替换 12 var news = _TEMPLATE_STRING.Replace("{url}", newsItem.Key).Replace("{title}", newsItem.Value); 13 14 html.AppendLine(news); 15 } 16 17 Trace.WriteLine(html.ToString()); 18 } 复制代码 其输出结果如下: 1 7名塔利班人员乔装女性 欲打入北约内部被捕
2 乌克兰遭轮奸焚烧少女伤重不治离世
3 国际空间站宇航员拍到北马里亚纳一火山喷发
4 土耳其同性恋男子可免除兵役 须提供确凿证据
5 英首相卡梅伦公布宴客名单 否认为筹款聚餐
6 孩子飞行途中胡闹不守秩序 全家四口被赶下飞机
7 男子上厕所时抽水马桶突然爆炸 大腿和背部受伤
8 美国总统奥巴马有意与林书豪切磋球艺
9 法国家长与教师联合抵制家庭作业 称加剧不平等
10 印尼政府称超短裙“色情” 欲对其颁布禁令
复制代码 正则表达式 正则表达式实现模板引擎说起来其实并不合适,大家也应该知道其最臭名昭著的就是性能。我们今天只是简单的提一下这种方案,并不算是真的要用它做一个模板引擎。但正则表达式技术在开发复杂的模板引擎是还是非常有用的。 FastReplacer 除了基本的字符串替换和正则表达式之外,这里我再介绍一种更加高效的替换方式——FastReplacer。原文地址:http://www.codeproject.com/Articles/298519/Fast-Token-Replacement-in-Csharp。 FastReplacer通过将字符串中指定格式的标记切分为Token,然后再做查找替换,其效率比字符串替换、正则表达式和StringBuilder要高出许多倍!详情请看原文介绍。这里我列举一下它的使用方法: 如果您有打算做一个查找替换式的模板引擎,那么FastReplacer可能会给你带来意想不到的性能优化! 1 /// 2 /// FastReplacer实现。 3 /// 4 [Test] 5 public void FastReplacer() 6 { 7 var html = new StringBuilder(); 8 9 foreach (var newsItem in this._newsItems) 10 { 11 // 您可以通过修改源代码为FastReplacer增加一个Clear方法 12 // 避免产生多个实例以提高性能 13 var fs = new FastReplacer("{", "}"); 14 fs.Append(_TEMPLATE_STRING); 15 16 fs.Replace("{url}", newsItem.Key); 17 fs.Replace("{title}", newsItem.Value); 18 19 html.AppendLine(fs.ToString()); 20 } 21 22 Trace.WriteLine(html.ToString()); 23 } 复制代码 以上是简单的查找替换方式的举例,因为不是本文的重点,也很好理解,也就不多说了(话说——写博客肿么这么累泥?)。 按流替代式 几个月前我第一次看到FastReplacer的时候,以为它内部用的也是流式替代,但仔细研究之后发现不是。那么到底什么是按流替代呢? 我们来看看如下的代码拆解(老陈所有的文章都是启发式的,因此在文字上不会下很大的工夫,偶滴词汇华丽的很不明显哇): {title}
这段代码其实可以看做以下代码的组合(这里以回车换行符隔开了): 1 4 {title} 5
复制代码 现在有没有感觉到眼前一亮呢?我们把这个字符串按照标记拆分成了5段,每一个小段,无论长短,我们都理解为Token。Token在流式解析当中是一个最基本的元素。 或许,到这里您已经看明白了,其实就是把模板代码按照一定的规则拆分成Token流,就类似于.NET内置的各种Stream一样,与字符串最接近的例如StringReader/StringWriter、XmlReader/XmlWriter等。使用.NET做Web开发的朋友一定对System.Web.HttpResponse再也熟悉不过了,它的Write()就是封装了一个字符串的流的写入操作,只不过这个流最终是写到HTTP网络连接上的。 话题转回来,我们要实现的流式替代就类似于如下过程: 1 // -------------------------------- 2 // 流程 3 // 6 // {title} --> 写为目标数据 7 //
8 // -------------------------------- 9 // 伪代码 10 foreach(var token in tokens) 11 { 12 if (token == "{url}") 13 { 14 Write("链接地址"); 15 } 16 else (token == "{title}") 17 { 18 Write("新闻标题"); 19 } 20 else 21 { 22 // 原原本本的输出 23 Write(token); 24 } 25 } 复制代码 看完代码,您要是再不明白什么是流式替代的话,那我真的要哭了! 不过,新的问题产生了——如何把模板代码变换为Token流呢?不要着急,这是下一节我们将要讲述的内容! 小结及代码下载 因为我的写作时间并不多,因此这里采用了单元测试的一些代码结构,不过对大家阅读和理解不会造成影响。 本文代码将与下一篇文章合并提供下载,祝各位工作顺利、开心快乐!

转载于:https://www.cnblogs.com/daoxuebao/archive/2012/04/01/2428048.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361558.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#锐利体验-第八讲 索引器与操作符重载(转)

第八讲 索引器与操作符重载 南京邮电学院 李建忠(cornyfield263.net) 索引 C#锐利体验 "Hello,World!"程序C#语言基础介绍Microsoft.NET平台基础构造类与对象 构造器与析构器方法域与属性索引器与操作符重载 数组与字符串特征与映射…

Java EE 7 / JAX-RS 2.0:具有自定义HTTP标头的简单REST API身份验证和授权

在使用已可用的HTTP协议实施Web服务时,REST带来了很多便利。 通过仅通过指定的URL触发GET,POST和其他HTTP方法,您将确保通过REST服务的响应来完成某些工作。 但是,无论REST给开发人员带来了什么便利,安全性和访问控制的…

关于form标签,你该知道

有没有发现,自己在写模板的时候很少使用form元素,一来form和table总是那么傻傻分不清楚;二来form的特性理解不清楚,有了input、label来了直接就上,根本不用form(不知道有没有人和我一样)。因此&…

一个微软面试题--关于位结构体

含位域结构体的sizeof: 前面已经说过,位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。 C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作…

easyui树形菜单实现

需求:读取路径配置中的相对路径获取对应的子文件夹及其子文件并形成树形结构,加载xml文件,输入搜索关键字匹配xml里面的value节点的值对应的contact值的集合并进行搜索 例如:输入b,找到xml里面的文本节点等于b的value…

在Twitter上使用Apache Mesos和Apache Aurora进行资源调度和任务启动

播客的第23集是与Bill Farner的谈话 Bill解释了Twitter如何使用Apache Mesos和Apache Aurora在硬件上获得更多收益,并通过在整个基础架构中利用细粒度的资源调度来节省工程时间(开发和运营)。 Bill谈到了他在Borg上与Google一起在Google上所…

fatal error C1083: 无法打开预编译头文件:“Debug\a.pch”:No such file or directory

一、解决方法 右键点击你创建的项目,选择“属性标签”点击属性,弹出“项目属性页”,在左侧找到以下位置 配置属性 --> C/C --> 预编译头,并选择它:在右边的菜单中选择 “创建/使用预编译头”中的“不使用预编…

ubunt 下 配置samba 服务器

一. samba的安装: sudo apt-get insall sambasudo apt-get install smbfs 二。修改/etc/samba/smb.conf sudo gedit /etc/samba/smb.conf 在smb.conf最后添加 [myShare]comment Shared Folder with username and passwordpath /home/wangywriteable yesbrowseable yesguest…

Telnet初试(本地测试)

win7下开启Telnet功能: 控制面板-程序和功能- 开启服务 然后回车 这样即可完成一次请求 更多专业前端知识,请上 【猿2048】www.mk2048.com

织梦dede 5.7系统基本参数无法修改保存,提示Token mismatch!

织梦dede 5.7系统基本参数无法修改保存,总是提示Token mismatch! 最开始以为是文件权限问题,反复给权限无法解决。 百度了下,也没有好用的方法 最后还是要自己动手 在dede/sys_info.php 54行找到对应的内容 根据代码判断是 $token变量问题 打…

您是否真的要加快Maven的编译/打包速度? 那么takari生命周期插件就是答案。

像你们中的许多人一样,我正在使用多模块Maven项目 。 与现有的许多系统相比,这不是一个很大的数目,它具有15个模块,3种不同的耳朵部署,带有属性文件的大量参数化以及大约10万行Java代码。 在开发高峰期,由于…

手机MMI体系结构及其实现

摘自:http://blog.csdn.net/zc2007/article/details/2340436 1引言 MMI(ManMachineInter-face),即人机界面,它负责和用户的交互,在必要的时候调用其它模块的功能。MMI模块在整个系统中处于最 高层&#x…

Aspose.Words简单生成word文档

Aspose.Words简单生成word文档 Aspose.Words.Document doc new Aspose.Words.Document(); Aspose.Words.DocumentBuilder builder new Aspose.W…

ubuntu下安装JDK和netbeans

我在ubuntu下安装netbeans十分简单,我下载了jdk-7u1-nb-7_0_1-linux-ml.sh,直接在终端输入 sh jdk-7u1-nb-7_0_1-linux-ml.sh安装的向导就会启动,你只要选择JDK和netbeans安装的目录,向导就自动替你安装jdk和netbeans,…

在带有组合框的值列表的下拉列表中显示显示属性的子集

组合框值列表(inputComboboxListOfValues)应该是使用LOV的非常流行的ADF Faces组件。 坦白说,这是我最喜欢的值列表方法。 在这篇简短的文章中,我将重点介绍ADF开发人员经常忽略的一项功能。 如果默认情况下定义了LOV,…

Cause: com.ibatis.common.xml.NodeletException: Error parsing XML. Cause: jav

报错:Cause: com.ibatis.common.xml.NodeletException: Error parsing XML. Cause: jav 原因:1、在对应的xml文件里面 #A#,只写了一个# 2、xml文件里面有多余的字符,如空格等 转载于:https://www.cnblogs.com/zzw3014/p/11316031.html

摆脱困境:在每种测试方法之前重置自动增量列

当我们为将信息保存到数据库的功能编写集成测试时,我们必须验证是否将正确的信息保存到数据库。 如果我们的应用程序使用Spring Framework,则可以为此目的使用Spring Test DbUnit和DbUnit 。 但是,很难验证是否在主键列中插入了正确的值&am…

仅坚持了9天:京东今日宣布暂停火车票代购业务

仅仅只坚持了9天,对于京东商城销售火车票的讨论一直进行着。不论是否具有销售资质,还是变相的收费。到今天下午为止京东商城发表声明暂停火车票代购业务。以下是京东公告全文:尊敬的京东网友:鉴于京东商城火车票代购业务测试期间出…

path.join 与 path.resolve 的区别

1. 对于以/开始的路径片段,path.join只是简单的将该路径片段进行拼接,而path.resolve将以/开始的路径片段作为根目录,在此之前的路径将会被丢弃,就像是在terminal中使用cd命令一样。 path.join(/a, /b) // a/bpath.resolve(/a, /b…

Android IPC系列(一):AIDL使用详解

概述 AIDL可以实现进程间的通信,由于每个进程都是运行在独立的空间,不同的进程想要交互需要借助一些特殊的方式,AIDL就是其中的一种,AIDL是一种模板,因为实际交互过程中,并不是AIDL起的作用,具体…