正则基础深入应用

本文是一篇真这个表达式的高级教程,主要通过一些例子,深入探讨正则表达式的高级功能。

写好正则首先第一点得对正则的支持都烂熟于心,第二点就是找到我们要取的数据的唯一特点。接下来我们通过几个例子来加强训练。

密码强度

密码必须包含大小写字母和字母和数字,排除特殊自字符,长度在6-12之间

用到了前瞻,如果还不清楚可以移步 正则基础学习

正则一

1
(?!^[a-z]+$)(?!^[0-9]+$)(?!^[A-Z]+$)^[a-zA-Z0-9]{6,12}$

其中 (?!) 这种写法是对后面数据的一种限定,过滤匹配的数据。如 (?!2)[0-9] 就是匹配除了2之外的所有数字。

然后,上面那段正则就可以分以下四段分析,因为(?!)只是限定条件,不匹配结果,所以前面三个(?!)只是三个条件,后面的才是匹配结果:

  • (?!^[a-z]+$): 排除纯小写
  • (?!^[A-Z]+$): 排除纯大写
  • (?!^[0-9]+$): 排除纯数字
  • ^[a-zA-Z0-9]{6,16}$: 匹配6到12个 [a-zA-Z0-9] 范围中字符

正则二

1
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{6,12}$

这段正则是上面的相反逻辑,所以结构有所不一样。上面那段正则是排除,这段正则是限定条件,所以^$ 位置不同。
这段正则分以下也三段分析:

  • ^(?=.*\d)[a-zA-Z0-9]{6,12}$: 匹配大小写字母以及数字,匹配的字符中必须有数字。
  • ^(?=.*[a-z])[a-zA-Z0-9]{6,12}$: 匹配大小写字母以及数字,匹配的字符中必须有小写字母。
  • ^(?=.*[A-Z])[a-zA-Z0-9]{6,12}$: 匹配大小写字母以及数字,匹配的字符中必须有大写字母。

整数部分千分位

现实中,土豪的存折里存的钱会是天文数字,没有千分位隔开,不好数自己的钱,
互利网中也是如此。
我们需要将数字整数部分加千分位,小数部分加千分位没必要,一般只精确到后两位。
因为js没有后瞻,所以首先大家可以将小数点前面的整数提取出来。

方法如下:

1
99999999999'.replace(/\d{1,3}(?=(\d{3})+)/g, '$&,');

  • (\d{3})+表示一组及以上3的倍数个数字加小数点
  • 然后用正向肯定查找 (?=) 包起来,说明 (\d{3})+ 只是一个条件
  • g 表示匹配多次直到没匹配到结果
  • $& 表示 \d{1,3} 正向查找条件成立时匹配到的结果

所以,这个正则匹配过程可以理解成:如果匹配到数字1~3个,如果后面的数字刚好是3的倍数,那就符合规则,$&提取再加上千分位符,接着继续匹配,知道读到百位后,已经不能满足\d{1,3} 后才停止匹配。

匹配身份证号码

正则匹配身份证号,根据身份证号码的规律,我们得出以下正则:

1
(?:1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|71|8[12])(?:(0[1-9])|[1-6][1-9]|70)(?:(0[1-9])|1[0-8]|[2-9][1-9])(?:(?:(19[0-9]{2}|200[0-9]|201[0-7])(?:(?:(?:0[1-9]|1[0-2])(?:0[1-9]|1[0-9]|2[0-8]))|(?:(?:0[13-9]|1[0-2])(?:29|30))|(?:0[13578]|1[02])31))|(?:(?:(19|20)(?:0[48]|[2468][048]|[13579][26]))|2000)0229)(?:[0-9]{3}[0-9X]);

正则分析

前六位地址码

百度百科上对于前六位中国大陆居民身份证号码中的地址码的数字编码规则解释:

华北地区: 北京市|110000,天津市|120000,河北省|130000,山西省|140000,内蒙古自治区|150000,
东北地区: 辽宁省|210000,吉林省|220000,黑龙江省|230000,
华东地区: 上海市|310000,江苏省|320000,浙江省|330000,安徽省|340000,福建省|350000,江西省|360000,山东省|370000,
华中地区: 河南省|410000,湖北省|420000,湖南省|430000,
华南地区: 广东省|440000,广西壮族自治区|450000,海南省|460000,
西南地区: 四川省|510000,贵州省|520000,云南省|530000,西藏自治区|540000,重庆市|500000,
西北地区: 陕西省|610000,甘肃省|620000,青海省|630000,宁夏回族自治区|640000,新疆维吾尔自治区|650000,
特别地区:台湾地区(886)|710000,香港特别行政区(852)|810000,澳门特别行政区(853)|820000

第一、二位表示省(自治区、直辖市、特别行政区)。
第三、四位表示市(地级市、自治州、盟及国家直辖市所属市辖区和县的汇总码)。其中,01-20,51-70表示省直辖市;21-50表示地区(自治州、盟)。
第五、六位表示县(市辖区、县级市、旗)。01-18表示市辖区或地区(自治州、盟)辖县级市;21-80表示县(旗);81-99表示省直辖县级市。

根据以上规则得出以下地址码正则:

  • 第一二位省码:(?:1[1-5]|2[1-3]|3[1-7]|4[1-6]|5[0-4]|6[1-5]|71|8[12])
  • 第三四位市码:(?:(0[1-9])|[1-6][1-9]|70)
  • 第五六位县码:(?:(0[1-9])|1[0-8]|[2-9][1-9])

中间八位生日期码

中间八位是生日器码,YYYYMMDD 格式。因为日期不仅有大小月,还有闰年,但是这里只需要19和20开头的闰年,正则长度小了不少。
首先从每个月都有的1-28号开始
(?:0[1-9]|1[0-2])(?:0[1-9]|1[0-9]|2[0-8])

然后除2月之外都有29号跟30号
(?:0[13-9]|1[0-2])(?:29|30)

接着1、3、5、7、8、10、12月有31号
(?:0[13578]|1[02])31

以上日期码前面再加上年 (19[0-9]{2}|200[0-9]|201[0-7]),这样子除了闰年的所有日期就都ok了,最后再来写闰年。
闰年的规则是能被4整除单不能被100整除,或者能被400整除。这里我们只写19和20开头的的年份。能被4整除不能被100整除的后两位
(0[48]|[2468][048]|[13579][26])
能被400整除的1900之后也就只有2000符合规则,2400年得过400年。这些年份写好了,再加上0229就ok了。
最后我我们用|连接起来。

1900到2017年
((?:(19[0-9]{2}|200[0-9]|201[0-7])(?:(?:(?:0[1-9]|1[0-2])(?:0[1-9]|1[0-9]|2[0-8]))|(?:(?:0[13-9]|1[0-2])(?:29|30))|(?:0[13578]|1[02])31))|(?:(?:(19|20)(?:0[48]|[2468][048]|[13579][26]))|2000)0229)

最后四位验证码

有了地区码和日期码,但是一个地方那一天出生的人肯定不止一人,所以就有了后四位。其中倒数第二个数字男的是单数女的双数,最后一位有可能是罗马数字的X:

1
([0-9]{3}[0-9X])