字符串校验的几种方式,正则表达式的效率分析
字符串校验的几种方式,正则的效率分析
问题
假如我们要校验一个字符串的格式是否正确,形式是名字*规格*件数,多个时用+号连接,最多出现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。(客户端回溯造成的影响是单个客户,不怕)