字符串校验的几种方式,正则表达式的效率分析

字符串校验的几种方式,正则的效率分析

问题

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

结束语:如果遇到了问题,欢迎在评论区交流,如果觉得不错,可以点赞和收藏,持续更新。

博客中标注原创的文章,版权归原作者 苦中作乐才是人生巅峰所有;转载或者引用本文内容请注明来源及原作者;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值