字符串连接
The + operator
1
str = "a" + "b" + "c";
The += operator
1
2
3str = "a";
str += "b";
str += "c";str += “one” + “two”;
会经历4个步骤:- 在内存中创建一个临时字符串;。
- 连接后的字符串”onetwo”被赋予给该临时字符串。
- 临时字符串与 str 当前的值连接。
结果赋值给 str。
1
2
3//这样做直接附加内容给 str,从而避免产生临时字符串。在大多数浏览器中会提速10%-40%
str += "one";
str += "two";1
2//简化为一个语句
str = str + "one" + "two";但是改变连接顺序(eg: str = “one” + str + “two”;),本优化将失效。
这些技术不适合 IE。在 IE7 及早期版本中结果只会更慢。是由 IE 执行连接操作的底层机制决定的。
array.join()
1
str = ["a", "b", "c"].join("");
- /
在大多浏览器中,数项合并比其它字符串连接方法更慢。但事实上,它却在 IE7 及更早版本浏览器中合并大量字符串唯一高效的途径。
- /
string.concat()
1
2str = "a";
str = str.concat("b","c");- /
在多数情况下,使用 concat 比使用简单的 + 和 += 稍慢,尤其在 IE、Opera 和 Chrome 中慢得更明显。
- /
正则表达式优化
正则表达式工作原理
- 编译
- 设置起始位置
- 匹配每个正则表达式字元
- 匹配成功或失败
回溯
回溯是匹配过程的基础组成部分。
量词,如* +? {2,}
分支,如 | 操作符
贪婪量词:
惰性量词:? (即匹配尽量少的字符)
回溯失控
当正则表达式导致浏览器假死数秒、数分钟,甚至更长时间,问题很可能是因为回溯失控。
(天呐,我看了书好几遍,还是没搞懂回溯怎么进行的!!)
目标字符串:<p>Para1.</p>
贪婪量词:/<p>.*</p>/i 第16步找到匹配项
惰性量词:/<p>.*?</p>/i 第22步找到匹配项
解决方案:
- 具体化
尽可能具体化分隔符直接的字符串匹配模式。如模式“.?”,它用来匹配一个由双引号包围的字符串。可以把 .\? 替换为更具体的 [^”\r\n]*,就去除了回溯时可能发生的几种情况。 - 使用预查和反向引用的模拟原子组
支持“原子组”特性的正则表达式引擎,包括.NET、Java、Oniguruma、PCRE 和 Perl。一旦原子组中存在一个正则表达式,该组的任何回溯位置都会被丢弃。
写法:(?>…)
But! JavaScript 不支持原子组。但是可以利用预查过程中的行为来模拟原子组:预查也是原子组。
提高正则表达式效率的方法
- 关注如何让匹配更快失败
- 正则表达式以简单、必需的字元开始
- 使用量词模式,使它们后面的字元互斥
- 使用非捕获组
- 值捕获感兴趣的文本以减少后处理
- 暴露必需的字元
- 使用合适的量词
- 把正则表达式赋值给变量并重用它们
- 将复杂的正则表达式拆分为简单的片段
何时不使用正则表达式
只是搜索字面字符串时会弄巧成拙。
如:检查一个字符串是否以分号结尾,可能用如下表达式1
endsWithSemicolon = /;%/.test(str);
但是浏览器并不是小机灵,它只会逐个测试整个字符串。最好的解决方法是1
endsWithSemicolon = str.charAt(str.length - 1) == ";";
去除字符串首尾空白
- 使用正则表达式去首尾空白
1
2
3
4
5if(!String.prototype.trim){
String.prototype.trim = function(){
return this.replace(/^\s+/,"").replace(/\s+$/,"");
}
}
其中有5种方法,这个是更好的解决方案
- 不实用正则表达式去除字符串首尾空白
1
2
3
4
5
6
7
8
9
10
11
12String.prototype.trim = function(){
var start = 0,
end = this.length - 1,
ws = " \n\r\t\f\x0b\xa0\u1680......\ufeff";
while (ws.indexOf(this.charAt(start)) > -1){
start++;
}
while (end > start && ws.indexOf(this.charAt(end)) > -1){
end--;
}
return this.slice(start, end + 1);
}
弱点:不宜用来处理前后大段的空白字符。
- 混合解决方案
用正则表达式方法过滤头部空白,用非正则表达式的方法过滤尾字符。1
2
3
4
5
6
7
8
9String.prototype.trim = function(){
var str = this.replace(/^\s+/,""),
end = str.length - 1,
ws = /\s/;
while (ws.test(str.charAt(end))){
end--;
}
return str.slice(0, end + 1);
}
所有 trim 方法的总的趋势是:在基于正则表达式的方案中,字符串的总长度比修剪掉的字符数量更影响性能;而非正则表达式方案从字符串末尾反向查找,不受字符串总长度的影响,但明显收到修剪空格的数量的影响。
简单地使用2次子正则表达式在各种浏览器处理不同内容及长度的字符串是,提供了更一致的性能表现,所以它被证明是最周全的解决方案。