javascript模板引擎

一直以来JavaScript对字符串的操作比较弱,特别是做.NET的人很清楚,犹如:String.Form格式化、StringBuilder大量字符串拼接每天都是离不开。故而也会在JavaScript上模拟这些。

String.Format

其实说白一点即是字符替换,这也是模板引擎最初级做法。而这里我提供一个我多年的示例:

/**
 * demo {@code 'this is the {0}'.format('end'); }
 */
String.prototype.format = function () {
    var args = arguments;
    return this.replace(/\{(\d+)\}/g, function (m, i) {
        return args[i];
    });
};

非常简单,但很耐用且是不是比.NET更优雅呢?当然这也只能{0}…{∞}来替换字符串,并无任何实际的运算能力或格式化能力。

且因为我们还会遇到另一种问题,就是当{}过多的时候,维护变得很困难。所以我们需要另一个高级点的办法。

String.Form变体

先看示例:

String.prototype.format = function () {
    var args = arguments;
    if (args.length == 1 && typeof(args[0]) === 'object') {
        return this.replace(/\{([\w\d]+)\}/g, function (m, i) {
            return args[0][i];
        });
    } else {
        return this.replace(/\{(\d+)\}/g, function (m, i) {
            return args[i];
        });
    }
};

相比较只是将{0}变成{Variable}一个比较有意义的变量名。这两种调用方法如下:

alert('ID:{0},UserName:{1}'.format('1', 'cipchk'));
alert('ID:{ID},UserName:{UserName}'.format({ ID: 1, UserName: 'cipchk' }));

以上倒是可以非常简单的完成字符串替换工作,接下来我们还需要一个很重要的东西,字符串拼接:

StringBuilder

.net为何会提出StringBuilder就是由于字符串+=会倒置内存空间的重新定义。Javascript的String跟.NET是相同问题,所以经常会听到在JavaScript里面使用Array和Array.Join来代替传统的+=,毋庸置疑网上有非常多评测来验证这个问题。

其实不然,+=速度慢那只是针对于传统浏览器比如:IE8以前、FF2.x以前。而现代浏览器+=比Array.push快,特别是V8下速度快4.7倍。所以结合两种方式才是最合理的。

看一下我的StringBuilder版本:

function StringBuilder() {
    this.isNewEngine = ''.trim;
    this.strings = this.isNewEngine ? '' : [];
}
StringBuilder.prototype.append = function (a) {
    this.isNewEngine ? this.strings += a : this.strings.push(a);
};
StringBuilder.prototype.toString = function () {
    return this.isNewEngine ? this.strings : this.strings.join('');
};
StringBuilder.prototype.clear = function () {
    this.isNewEngine ? this.strings = '' : this.strings.length = 0;
};
var html = new StringBuilder();
html.append('1');
html.append('2');
document.write(html.toString());

为何我要先介绍字符串替换和拼接,因为目前任何一种模板引擎都离不开这2个。

而对于模板引擎的定义是:为了使用户界面与业务数据(内容)分离。而从这个定义上出发,我们可以适当的缩小运用于JavaScript范围的说法,比如说成:将HTML和数据模型的分离。

且这种分离不在是简单的字符串拼接,首先必须满足:效率、灵活、运算能力、丰富功能、缓存、插件、开源等等。好吧,我骗你,这有些要求过高;因为我们只需要一个很简单的模板引擎,因此重点是在:效率、灵活上。

artTemplate

这是我见过最小、高性能模板引擎。请看这有一篇作者很详细介绍。其中重点是:预编译和字符串拼接效率极限;包括自带错误调试。

doT

也是一个短小的家伙,相比较artTemplate灵活性更高,同时支持Node.js。

哎,我又不想写示例了,就这样子吧。

正则表达式笔记系列-匹配原理

以下是来自孟岩CSDN博客对两类正则引擎做的解释,我觉得挺好的。

正则表达式引擎分成两类,一类称为DFA(确定性有穷自动机),另一类称为NFA(非确定性有穷自动机)。两类引擎要顺利工作,都必须有一个正则式和一个 文本串,一个捏在手里,一个吃下去。DFA捏着文本串去比较正则式,看到一个子正则式,就把可能的匹配串全标注出来,然后再看正则式的下一个部分,根据新 的匹配结果更新标注。而NFA是捏着正则式去比文本,吃掉一个字符,就把它跟正则式比较,匹配就记下来:“某年某月某日在某处匹配上了!”,然后接着往下 干。一旦不匹配,就把刚吃的这个字符吐出来,一个个的吐,直到回到上一次匹配的地方。

而.NET就是传统性的NFA正则引擎。

一、匹配基础

规则1:优先选择最左端的匹配结果

简单来说,当你的表达式可以匹配多个结果出来的时候,最左边的结果优先于其他结果。直接一点说就是只得到第一匹配结果。

用[哪里]来匹配:在哪里跌倒,就在哪里躺下。

结果是【在哪里跌倒】而不是【就在哪里躺下】,由于【在哪里跌倒】中的【哪里】出现得更早。这个比喻很烂,来自书上的一个示例:

用[fat|cat|belly|your]来匹配:The dragging belly indicates that you cat is too fat.

结果并不是【fat】而是【belly】,因于NFA加规则1所以他的结果就是这样

规则2:标准量词是匹配优先的

记住:NFA正则引擎是拿着表达式来匹配文本的。

尝试匹配尽可能多的字符,直接匹配上限为止。

比如:用[\b\w+s\b]来匹配[regexes],[\w+]是能够完全匹配整个单词,但是如果用[\w+]来匹配整个单词那就无法匹配[s\b]。而为了完成匹配,[\w+]就必须吐出一个[s]并把它保留给[s\b]来匹配。这个示例中告诉我们两个原则。

A:过度的匹配优先原则

说的是[\w+]她会一直吃吃吃吃吃直到整行结束,然而[s\b]是必须匹配的,所以[s\b]会拿着一把枪对着[\w+]说:“兄弟,你吃太多了,交出一些字符出来吧,没准我也可以匹配”,在枪的作用下[\w+]只好乖乖的吐一字符让[s\b]去玩,结果匹配上了,那么整个表达式匹配成功。

B:先来先服务原则

而为什么只需要吐一个呢?原因就是[s\b]最低下限只需要一个字符即可。谁叫[\w+]优先匹配到,那么她就享受到先服务的原则。

二、比较NFA、DFA

直接一点的说DFA比NFA更快。但是NFA为创造性思维提供了丰富的施展空间,假设有三种方式对某一文本进行匹配得到结果一样,那么这三种写法不同的正则,她的有效率也就不一样。当然了,前提必须是你要了解NFA的原理。而NFA最重要的部分:回溯(backtracking)。

三、回溯

其实前面那吐的过程就是一个回溯。就像走迷宫一样当遇到分支的时候你做个记号,然后选择其中一条走,当无法走出去的时候,你再回到那个做记号的位置走另一条。

在众从选择时,哪些分支应当首先选择?回溯过程中又是如何保存状态的?

对于匹配优先量词,引擎会优先“进行尝试”,而对于忽略优先量词进行“跳过尝试”。距离当前最近储存的选项就是当本地失败强制回溯时返回的,使用的原则就是LIFO(last in first out 后进先出)。

明白这个道理写出高效的正则表达式非常有帮助。

正则表达式笔记系列-常用元字符和特性

一个完整的正则表达式是由元字符和其他“文字”构成的,单个元字符就是正则表达式的最小单元,丰富的元字符提供强大的描述能力。我把正则表达式看成一种独立处理功能。那么在不同环境(Windows、MacOS…)、语言(.NET、Java、Python、Perl、PHP、MySQL、MSSQL、Ruby…)上面它会有很些差异,比如:字符串、字符编码、匹配模式。

一、字符串

这里的字符串是指正则引擎接收的字符串,我们知道一串字符串是用一对双引号标注,反斜线是元字符,但是在不同语言上面它们要表达同一个元字符有区别的。

JAVA:

Pattern regex = Pattern.compile("\\d", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.MULTILINE);

C#:

Regex regexObj = new Regex(@"\d", RegexOptions.IgnoreCase | RegexOptions.Multiline);

不同之处是\\d和\d的区别。至少C#看起来更简洁一点(@代表字符串是原生字符串,这种方式PHP同样也支持,当然还有更多)。

二、字符编码

字符编码是一种写明的共识,它规定不同数值的字节应该如何解释。

由于正常情况下不需要人工干涉所以我对这一节只是做一个了解而已。懒啊···· 😥

三、匹配模式

许多正则引擎都支持多种不同的模式,它们规定了正则表达式应该如何解释和应用。

我觉得我还是整理一下我常用的语言(C#)单独深入讨论。

常用的元字符和特性

以下是我用大量时间去整理出来,我针对.NET的一张表格,算是做为我个人的手册之一:

描述
字符表示法 单词分界符 \b、退格字符 \b、警报 \a、ASCII Escape \e、进纸符 \f、换行符 \n、回车符 \r、制表符 \t
字符组相关
  • [a-z]和[^a-z]普通字符组:它表示肯定断言也就是说必须匹配一个字符。[0-9]和[0123456789]速度上是一样的,我尝试在.NET平台下面做速度测试[0-9]表示法略胜一筹。
  • .点号:匹配任何字符的字符组。
  • 字符组简记法:
    1. \w:单词中的字符等价于[a-zA-Z0-9_],支持Unicode。
    2. \W:非数字等价于[^\w]
    3. \d:数字等价于[0-9]
    4. \D:非数字等价于[^\d]
    5. \s:空白字符等价于[空格\f\n\r\t]
    6. \S:非空白字符等价于[^\s]
  • 反向引用
锚点、零长度断言 锚点、零长度断言并不会匹配实际的文本,而是寻找文本中的位置。




  • ^、\A:匹配字符串起始位置
  • $、\Z:匹配字符串结束位置,也可以匹配字符串结尾的换行符
  • \z:只匹配字符串的末尾,不考虑任何换行符
  • \b、\B:匹配字符串的某些位置,开始和结束都用\b表示(\B:表示非单词分界符)。.NET单词分界符等于\w,PS:所有正则引擎都不会对单词进行语意分析。
  • 顺序环视(?=…)、(?!…);逆序环视(?<=…)、(?<!…):正常情况下用得比较少,但是我得专门一篇来复习它,至少我觉得它是非常棒。
分组、捕获、条件判断、控制
  • 捕获/分组括号:(…)、\1、\2…
  • 仅用于分组的括号:(?:…)
  • 命名捕获:(?<Name>)
  • 多选结构:…|…
  • 条件判断:(?if then|else)非常有趣应该单独说明。恩恩。
  • 量词:
    1. {n,m}:m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次
    2. *:匹配零次或多次
    3. +:匹配一次或多次
    4. ?:匹配零次或一次
注释和模式修饰符
  • 模式修饰符:(?i)
    i 不区分大小写 RegexOptions.IgnoreCase
    s 点号能匹配任何字符 RegexOptions.Singleline
    x 宽松排列和注释模式 RegexOptions.IgnorePatternWhitespace
    m 多行模式 RegexOptions.Multiline
    n 关闭(…)的捕获功能,只有(?<name>…)能够捕获 RegexOptions.IgnoreCase

参考资料

  1. 各种工具之正则表达式语法比较(转自永恒蓝哲
  2. 正则表达式

正则表达式笔记系列-工具篇

学习的开始我总会先给自己制造一个环境,而对于正则表达式你只需要挑选一个自己喜欢的工具就行拉,有人已经专门过做这些方面的介绍而从国外到国内都做非常详细说明。而我个人用的是RegexBuddy 3虽然不是最新版的,但是功能已经足够我用,而且还是完全版,不需要MONEY这才是主要的,哇哈哈····· :mrgreen:

  1. windows下的正则式工具介绍之一:RegexBuddy
  2. windows下的正则式工具介绍之二:powergrep

正则表达式笔记系列-开篇

我不知道第几次看《第一滴血》这一系列电影,也许是被蓝波这个角色给吸引。情节的好坏是随着时代的改变而改变的,而他的意念和那把不离身的刀是永远不会被改变。于是开篇也跟随《第一滴血3》任务的前进而前进。

正则表达式从较低层面上来说,正则表达式描述的是一串文本的特征。你可以用她验证用户输入数据或者检索大量文本。从较高层面上来说,正则表达式容许用户掌控他们自己的数据,控制这些数据让他们为你服务。掌握正则表达式,你将拥有一个能帮助你说话的数据工具。

由于大部分情况下都是使用C#做为开发语言,所以例子也按C#为准,当然正则表达式在不同语言环境下面有不同的差异,目前不考虑其他语言的情况。

我希望将记录下来的笔记能够加深我对正则表达式的理解,因为我知道:“如果你是一本书的作者,那只有作者才能真正理解内容”。头一次将它变成属于我自己的“书”。

© 2017 卡片机色彩 沪ICP备13032872号-3

Theme by cipchk

to top