关于数字的正则验证

数字正则验证

自己在实际工作过程中,发现正则用到的地方很多,而且写的好的正则表达式可以在达到同样效果的情况下更简洁美观,性能也更佳。本人对于正则是十分推崇喜爱的,也一直在学习此的过程中,其中也有一些心得体会,借此分享给大家。

正则的基础语法我就不多介绍,可以参阅菜鸟正教程,也可以看看百度正则词条来直接学习使用正则语法。在日常使用过程中,很多时候我们需要对数字进行正则,数字正则看似简单,实则里面也有很多技巧,通过自己的实践将一些心得分享一下。

常见的,以匹配18位身份证号的数字正则举例:
匹配18位的身份证号,首先想到的是18位和数字这两个条件,可以得出(\d){18},解读一下,\d匹配为[0-9],表示0到9的数字,整个表达式的意思是0到9的正整数18个;
仔细一想,身份证首位不存在0,最后位可能为X(罗马数字的10),改良以后得到[1-9]\d{16}(\d|X|x)
这样似乎已经解决问题了,但其实不然,正则表达式的使用,其中很重要的一点就是要精准,何谓精准,主要体现在漏匹配误匹配两个方面上,顾名思义,漏匹配是指正则表达式所匹配的内容范围太过狭窄,导致某些符合要求的内容没有匹配到,就像前文中的身份证最后位可能为X,如果我们只考虑数字而忽略了末位为X这种情况,就属于漏匹配;而误匹配也很好理解,指正则表达式所匹配的内容范围太过宽泛,有些很明显不符合我们匹配要求的,也可以被匹配成功,例如前文中首位为0的情况,很明显身份证不存在首位为0的情况,如果使用\d而不是[1-9]就属于误匹配。
由此,我们可以知道,正则的正确率体现在无漏匹配上,而正则的效率则体现在低误匹配率上,很多时候,在使用一段时间正则后,无漏匹配一般都能做到,但在低误匹配率上,会发现与那些熟练使用正则的大佬还是有所差距(最为理想的情况是无漏匹配且无误匹配),所以我们平时在使用正则表达式过程中,应当遵循在保证正确率的情况下,应该尽可能减低组件的误匹配率。所以,当我们再看到[1-9]\d{16}(\d|X|x)用于匹配18位身份证号码时,就觉得不够看了,我们需要了解更多的规则限制,才能减低误匹配率。查询相关资料,我们可以发现,18位的身份证是由多部分构成的:
前1、2位数字表示:所在省份的代码,且首位不存在0;
第3、4位数字表示:所在城市的代码;
第5、6位数字表示:所在区县的代码;
第7~14位数字表示:出生年、月、日;
第15、16位数字表示:所在地的派出所的代码;
第17位数字表示性别:奇数表示男性,偶数表示女性;
第18位数字是校检码:用来检验身份证的正确性。校检码可以是0~10的数字,10用x表示。
综上所述,我们可以再排除一些情况,比如7-10的出生年份,很明显应该没有18世纪或者21世纪的人,19世纪的人现在也起码120岁了(18世纪的级之前的怕是看了《这个男人来自地球》吧,就算如此用的也是假身份证吧),所以应该只有存在18,19,20开头的,当然我们考虑到未来,顺延一段时间,将2和3开头的都先考虑进去好了;然后11到12位表示月份,很明显只有12种情况,13到14位表日期,最多只有31种可能。先将上诉内容归纳,我们可以得到正则表达式:

^[1-9]\d{5}(18|19|([2-3]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}(\d|X|x)$`

相比[1-9]\d{16}(\d|X|x),看似麻烦不少,可能有人会觉得没有必要,用后面那种不是更简便吗,但是我们就只看7,8位,相比以前的2个\d,使用18,19,2和3开头的正则,只需要匹配相当于原来1/5作用的内容,这里就可以少匹配80%,更何况还有一些其他情况,很多时候都是几个数量级的优化量,所以正则匹配性能优化时由优化表达式带来的优化量十分可观。
另外从上诉正则不断优化过程中,不难总结出一些书写正则表达式时的行之有效的经验:
1、先做加法,再做减法:一开始用正则进行匹配界定时,可以先将范围放宽些,然后慢慢做减法,一步步缩减范围。如上面匹配身份证号码时,我们一开始完全可以用[1-9]\d{16}(\d|X|x)这种完全不考虑身份证号码各位数规则,只考虑数字这样的表达式,目的是为了保证我们的正确率(无漏匹配),因为正确率是第一位的,如果连正确率都不能保证(存在漏匹配),那我们的正则一开始就是错的,何谈优化,优化得再怎么完美都是白搞。
2、按部就班,循序渐进:在做减法的时候,要按照我们能获取到的条件,一步步,一层层地”改进“我们的正则表达式,初用正则时,切不可想着一步到位,一开始就在那里空想,想直接一下子就把所有内容都完成,这是不切实际的,或者说是一开始使用正则时极难达到的。我们在解决问题的时候,可以将问题分为一个个小问题,分为很多小部分,一点点剖析开来,就像前面的身份证号码正则,我们完全可以将其分为前6位,中8位,倒数234位,末尾这四个部分,一点点分析,一个个解决。正如小时候学过的莫顿·亨特的文章《走一步,再走一步》(原名《悬崖上的一课》),就不怕遇到难题,也可以极大的提升正确率。
3、留有余地,正如我们平时做事时一样,很多时候考虑和解决问题都需要我们留有余地,留有“操作”空间,就像前面考虑年份时,虽然我们在限定20实际的时候,完全可以限定200,201,202这三个开头(表示2000-2030年间),因为还有10年才会出现其他情况(本文写于2020年),尽管包含了所有目前2000年及之后的情况,但是未免限定的太过于狭窄,所以我们限定时包含了所有的2和3开头的情况,倒不是说我们想让我们的正则使用周期能有几千年跨度这么久,而是想体现一种前瞻性思维,目的是降低漏匹配率,延长正则表达式的生命周期。
4、多做多练,所谓熟能生巧,做任何事都一样,每个人的天赋可能会有所差别,一开始入手时会有所差异,但勤能补拙,我们可以通过不断地练习来提升我们的熟练度。那些熟练应用书写高效率正则的人,也都是从一开始的懵懂,通过不停地实践、练习提升自己的技能水平,才到达融会贯通的水平的。

写在最后:自己在正则方面也谈不上驾轻就熟,像非捕获型括号(?:…)相对于普通括号()对于内存的优化、较为复制正则的书写等方面,至今还又很大不住,写这篇文章是讲述一些自己的心得体会,希望大家能够一起成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值