字符串校验的几种方式,正则的效率分析
问题
假如我们要校验一个字符串的格式是否正确,形式是名字*规格*件数,多个时用+号连接,最多出现5次,件数最大999
例如:品名1*规格1*100+品名2*规格2*100";
正则效率
很显然,我们只需要一个正则就可以搞定
const NAME = "品名1*规格1*100+品名2*规格2*100";
const reg = /^(([^*+]+\*){2}\d{1,3}($|\+[^$])){1,5}$/g;
console.log(reg.test(NAME))
效率如何呢?我们以百万次运行为基准
const NAME = "品名1*规格1*100+品名2*规格2*100";
const NAME2 = "品名1*规格1*100+品名2*规格2*100*";
const NAME3 = "品名1*规格1*10*100+品名2*规格2*100";
const NAME4 = "+品名1*规格1*100+品名2*规格2*100";
const reg = /^(([^*+]+\*){2}\d{1,3}($|\+[^$])){1,5}$/g;
const NAMES = [NAME,NAME2,NAME3,NAME4];
NAMES.forEach(NAME=>{
console.log(NAME);
console.time("正则耗时:");
for(let i=0;i<1000000;i++){
reg.test(NAME)
}
console.timeEnd("正则耗时:");
console.log(reg.test(NAME));
});
原生JS
下面我们来书写一个原生JS函数来校验这个字符串,我们尽可能将JS优化的高效点
function test2(NAME) {
if(NAME[0]==="*")return false;
let i=0, insideLoopNumber=0, outSideLoopNumber=0, numberLoopNumber=0;
const len=NAME.length;
while (i<len){
const code = NAME.charCodeAt(i);
if(code===43){
if(insideLoopNumber!==2)return false;
const next = NAME.charCodeAt(i+1);
if(!next||next===43||next===42)return false;
if(++outSideLoopNumber>5)return false;
numberLoopNumber=0;
insideLoopNumber=0;
}else if(code===42){
const next = NAME.charCodeAt(i+1);
if(numberLoopNumber!==0||!next||next===42||next===43||++insideLoopNumber>3)return false;
}else if(insideLoopNumber===2){
if(code>57||code<48)return false;
if(++numberLoopNumber>3)return false;
if(!NAME.charCodeAt(i+1))return true
}
i++
}
return outSideLoopNumber!==0
}
效率如何呢?我们继续以百万次运行为基准
const NAME = "品名1*规格1*100+品名2*规格2*100";
const NAME2 = "品名1*规格1*100+品名2*规格2*100*";
const NAME3 = "品名1*规格1*10*100+品名2*规格2*100";
const NAME4 = "+品名1*规格1*100+品名2*规格2*100";
const NAMES = [NAME,NAME2,NAME3,NAME4];
NAMES.forEach(NAME=>{
console.time("while耗时:");
for(let i=0;i<1000000;i++){
test2(NAME)
}
console.timeEnd("while耗时:");
console.log(test2(NAME));
});
split函数
实际业务代码为了可读性,我们更多的是使用split来检验,通俗易懂,但性能方面就差了很多。
function testSplit(txt) {
const arr=txt.split("+");
if(arr.length>5)return false;
for(let i=0;i<arr.length;i++){
const _arr=arr[i].split("*");
if(_arr.length!==3||!_arr[0]||!_arr[1]||!_arr[2])return false;
if(isNaN(Number(_arr[2])))return false
}
return true
}
性能对比
由此可以看出一点端倪。
总结
正则在弱类型解释型语言(其实我只测试了js)运行速度非常快,得益于底层的支持,实际是执行的底层代码比js效率高,虽然我们自己的while循环已经非常快了,尤其是错误在后面的时候,和正则还是有一定差距的,
综合来看,不同的方式耗时上,正则<while循环<split分割法
具体使用哪种方式取决于正则能否直接满足业务的逻辑,如果可以,推荐使用正则表达式。
注意:服务器语言在使用正则时一定要注意*+{}的使用,否则造成的回溯问题会直接打满cpu。(客户端回溯造成的影响是单个客户,不怕)
结束语:如果遇到了问题,欢迎在评论区交流,如果觉得不错,可以点赞和收藏,持续更新。
博客中标注原创的文章,版权归原作者 苦中作乐才是人生巅峰所有;转载或者引用本文内容请注明来源及原作者;