受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术。本系列文章将会带您由浅入深的全面认识模板引擎的概念、设计、分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎。关于模板引擎的概念,我去年在百度百科上录入了自己的解释(请参考:模板引擎)。老陈曾经自己开发了一套网鸟Asp.Net模板引擎,虽然我自己并不乐意去推广它,但这已经无法阻挡群友的喜爱了!

很显然,置换型模板引擎说的就是替换式模板引擎。它的工作原理是查找和替换字符串,但这个字符串的替换过程又分为直接查找替换和按流替代输出两种。直接查找替换实现简单,但存在一定的性能障碍,而按流替代的方式性能更好一点,但理解起来却没那么容易。今天我们就专门来讨论讨论置换型模板引擎的关键技术和实现。

概念

按照不同的置换方案,置换型模板引擎分为查找替换式按流替代式两种。查找替换式又分为字符串替换正则替换两种

大家应该都很理解查找替换式模板引擎的含义了,它就是把定义好的标记替换为我们需要的内容即可。而按流替代式虽然在结果上也是将我们指定的标记“替换”为了实际内容,但它内部并没有用到Replace()这种方式,而是在遇到标记的时候直接写出对应的内容,它实际上没有所谓的替换操作,因此性能会好一些。

查找替换式

查找替换这个词大家已经是再也熟悉不过了,我们几乎每天都要编写一次或几次Replace()代码。而查找替换也是构建模板引擎的最基本的思想,任何模板引擎的机制归根结底都还是查找替换。假设我们有如下模板代码和业务数据:

 1 /// <summary>
 2 /// 模板文本。
 3 /// </summary>
 4 private const string _TEMPLATE_STRING = @"<a href=""{url}"">{title}</a><br />";
 5
 6 /// <summary>
 7 /// 业务数据。
 8 /// </summary>
 9 private Dictionary<string, string> _newsItems = new Dictionary<string, string> {
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 /// <summary>
 2 /// 最简单的模板引擎。
 3 /// </summary>
 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 <a href="http://news.qq.com/a/20120330/001077.htm">7名塔利班人员乔装女性 欲打入北约内部被捕</a><br />
 2 <a href="http://news.qq.com/a/20120330/001409.htm">乌克兰遭轮奸焚烧少女伤重不治离世</a><br />
 3 <a href="http://news.qq.com/a/20120330/001288.htm">国际空间站宇航员拍到北马里亚纳一火山喷发</a><br />
 4 <a href="http://news.qq.com/a/20120330/001535.htm">土耳其同性恋男子可免除兵役 须提供确凿证据</a><br />
 5 <a href="http://news.qq.com/a/20120330/000874.htm">英首相卡梅伦公布宴客名单 否认为筹款聚餐</a><br />
 6 <a href="http://news.qq.com/a/20120329/001774.htm">孩子飞行途中胡闹不守秩序 全家四口被赶下飞机</a><br />
 7 <a href="http://news.qq.com/a/20120329/001771.htm">男子上厕所时抽水马桶突然爆炸 大腿和背部受伤</a><br />
 8 <a href="http://news.qq.com/a/20120329/001685.htm">美国总统奥巴马有意与林书豪切磋球艺</a><br />
 9 <a href="http://news.qq.com/a/20120329/001696.htm">法国家长与教师联合抵制家庭作业 称加剧不平等</a><br />
10 <a href="http://news.qq.com/a/20120329/001650.htm">印尼政府称超短裙“色情” 欲对其颁布禁令</a><br />

正则表达式

正则表达式实现模板引擎说起来其实并不合适,大家也应该知道其最臭名昭著的就是性能。我们今天只是简单的提一下这种方案,并不算是真的要用它做一个模板引擎。但正则表达式技术在开发复杂的模板引擎是还是非常有用的。

FastReplacer

除了基本的字符串替换和正则表达式之外,这里我再介绍一种更加高效的替换方式——FastReplacer。原文地址:http://www.codeproject.com/Articles/298519/Fast-Token-Replacement-in-Csharp。

FastReplacer通过将字符串中指定格式的标记切分为Token,然后再做查找替换,其效率比字符串替换、正则表达式和StringBuilder要高出许多倍!详情请看原文介绍。这里我列举一下它的使用方法:

如果您有打算做一个查找替换式的模板引擎,那么FastReplacer可能会给你带来意想不到的性能优化!

 1 /// <summary>
 2 /// FastReplacer实现。
 3 /// </summary>
 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的时候,以为它内部用的也是流式替代,但仔细研究之后发现不是。那么到底什么是按流替代呢?

我们来看看如下的代码拆解(老陈所有的文章都是启发式的,因此在文字上不会下很大的工夫,偶滴词汇华丽的很不明显哇):

<a href="{url}">{title}</a><br />

这段代码其实可以看做以下代码的组合(这里以回车换行符隔开了):

1 <a href="
2 {url}
3 ">
4 {title}
5 </a><br />

现在有没有感觉到眼前一亮呢?我们把这个字符串按照标记拆分成了5段,每一个小段,无论长短,我们都理解为Token。Token在流式解析当中是一个最基本的元素。

或许,到这里您已经看明白了,其实就是把模板代码按照一定的规则拆分成Token流,就类似于.NET内置的各种Stream一样,与字符串最接近的例如StringReader/StringWriter、XmlReader/XmlWriter等。使用.NET做Web开发的朋友一定对System.Web.HttpResponse再也熟悉不过了,它的Write()就是封装了一个字符串的流的写入操作,只不过这个流最终是写到HTTP网络连接上的。

话题转回来,我们要实现的流式替代就类似于如下过程:

 1 // --------------------------------
 2 // 流程
 3 // <a href="
 4 // {url} --> 写为目标数据
 5 // ">
 6 // {title} --> 写为目标数据
 7 // </a><br />
 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流呢?不要着急,这是下一节我们将要讲述的内容!

小结及代码下载

因为我的写作时间并不多,因此这里采用了单元测试的一些代码结构,不过对大家阅读和理解不会造成影响。

本文代码将与下一篇文章合并提供下载,祝各位工作顺利、开心快乐!

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

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

    受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...

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

    受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...

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

    受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...

  4. 由浅入深:自己动手开发模板引擎——解释型模板引擎

    受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...

  5. 由浅入深:自己动手开发模板引擎——解释型模板引擎(二)

    受到群里兄弟们的竭力邀请,老陈终于决定来分享一下.NET下的模板引擎开发技术.本系列文章将会带您由浅入深的全面认识模板引擎的概念.设计.分析和实战应用,一步一步的带您开发出完全属于自己的模板引擎.关于 ...

  6. freemarker ftl模板_Web开发人员必会的模板引擎技术之Freemarker

    曾几何时,Web开发是个多么高大上的名字,程序猿们都以能搞定Web技术为荣,此时还没有前后端之说.然而随着互联网的发展,社会分工进一步细化,职业岗位也更加细分,慢慢开始有了前端攻城狮和后端攻城狮,技术 ...

  7. beetl模板使用场景_Java 模板引擎 Beetl 2.0 发布

    Java开源模板引擎 Velocity Velocity是一个基于java的模板引擎(template engine).它允许任何人仅仅简单的使用模板语言(template language)来引用由 ...

  8. Django 3.2.5博客开发教程:一些常用的模板使用方法

    一.django static文件的引入方式 1.在django project中创建 static文件夹 2.settings.py中配置要在 STATIC_URL = '/static/' 下边 ...

  9. Angular 原理图 Schematics 学习 - 动手开发一个实际的例子

    当 ng add 命令向项目中添加某个库时,就会运行原理图.ng generate 命令则会运行原理图,来创建应用.库和 Angular 代码块. 一些术语: 规则 在原理图 中,是指一个在文件树上运 ...

最新文章

  1. Linux下载交通图片数据集CityScapes Dataset
  2. 【Python】一道题吃够Python语法糖
  3. JVM的内存配置参数
  4. MSP432 库函数实现 PID 电机调角度、调速
  5. swag您的装置不支持_一件充满意境的中国风水墨粒子、电子屏风交互装置
  6. MapGuide 浏览器可接受参数分析
  7. TypeScript 令我苦不堪言
  8. 华为轮值董事长郭平:5“机”协同是基础电力,ICT行业应用将像家用电器和工业电气化
  9. 结巴(jieba)分词器入门
  10. android语音识别 android.speech 包分析
  11. 在macOS Sierra 10.12.3下用VMware Fusion安装Ubuntu 16.04.2
  12. java 传递intent_intent传递参数
  13. PS3中文游戏合集下载
  14. Tableau学习教程(万字保姆级教程)​​​​​​
  15. java 转化箭头函数_this 指向详细解析(箭头函数)
  16. delphi控件属性和事件
  17. Android通知栏字体大小,Android通知栏介绍与适配总结(上篇)
  18. BH-02蓝牙耳机 超重低音蓝牙耳机
  19. 高效视频编码 (HEVC) -H.265(结构解析)
  20. 【Python】司徒卢威函数

热门文章

  1. POJ2239简单二分匹配
  2. hdu1305 字典树水题
  3. 【计算机网络】网络安全 : 数据加密模型 ( 加密模型 | 密钥 | 密码学 | 密码安全 )
  4. 【运筹学】线性规划 单纯形法 阶段总结 ( 初始基可行解 | 判定最优解 | 迭代 | 得到最优解 | 全流程详细解析 ) ★
  5. Exchange 2016证书配置
  6. 机器学习中的EM算法具体解释及R语言实例(1)
  7. 利用Python自动生成暴力破解的字典
  8. ssas 为绑定指定的大小太小,导致一个或多个列值被截断
  9. oracle connect by用法
  10. windows平台cl.exe编译pcre 8.13