正则表达式学习
今天小祖宗提了一个需求,输入框只能让他显示a|b|c格式,如果不是就给他报个提醒。我说你这东西遍历一遍不就得了,嫌代码多,要搞正则方便。
正则之前接触过,不过都是直接百度去找一个来直接用,这种特殊需求肯定没有现成的啊。怎么着呗,小祖宗提的需求就去学啊,诶。
多说一嘴,找现成的正则拉过来用其实没有问题,但是你要可以看懂他,就像代码一样的,到时候出错了你也不知道。
正则其实看起来比较麻烦,一堆符号堆在那里,其实是一个很简单的东西。他有一个普通字符,比如0-9这个就是表示0-9,a-z表示小写的a-z。这些东西是表示内容的,比如你要筛选全是数字的[0-9]可以满足了,有人说那我要是两位数呢。这个时候就要限定符号。限定符表示前面那个子表达式要出现几次,如下图。
前面几个特殊的先不提,先把{}这个记住,因为上面三种其实是{}对这个的缩写。{}表示前面的表达式的出现的次数,{2}表示出现2次,加个 , 表示2次及以上,再加一个数字就表示范围,{2,4}表示出现2到4次都是可以匹配的。
这里安利一个网站http://c.runoob.com/front-end/854,在线写正则,可以一遍写,一遍测试。
举例子说[0-9]{2,4},能过的是指长度为2和4之间的数字串。000和123和0001都是可以算的。如果单纯的想要表示两位数要[1-9][0-9]{1}。
然后讲一下[] ,这里的东西是用来表示需要选的数,可以放很多东西,比如[01ab],他会筛选0或1或a或b。但是不会选出ab,因为他只选一位,需要注意。 然后这里有个细节,为什么[01ab]选出来的是0或1或a或b,而[0-9]选出来是0-9的任意数字,而不是0或-或9。正则里的大部分的符号都是有他的限定意思的,那如果你要找这些符号怎么办,比如小祖宗提的需求里有|,这个在正则中是表示或,如果需要找这种特殊字符,需要加一个\,来表示转义符,转义符都清楚的就不多说了。
然后这种特殊字符都有记录,作用如下图
这图说的很清楚了,没必要一条条复述。稍微讲一下开始和结尾位置符号,这两个东西有点秀,比如说^[1-9],这个子表达式说明开始是1-9中的一个数字,然后[x]$表示结尾要用x。举个组合的例子^[1-9][0-9]*[x]$。这条表示开头必须是1-9,中间可以一堆数字,结尾必须是x。但是这个东西有点神奇,放在[]中表示取反,不取这里面的东西。比如[^0-9]就是取除了数字之外的所有东西。比方说^[^0-9]表示首字母不可以是数字,看到这个描述是不是很熟悉,已经可以用来做昵称审核了。
以上完成之后,基本的正则应该是能看懂了,这里拿一条网上的身份证的正则过来。^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$
这个\d表示数字,相当于[0-9]。她这个的意思就是,首先六个数字,然后四个数字,然后2个数字,然后两个数再三个数字,最后是数字和x的组合。这个其实可以等价于17位数字+最后一位0-9或x。说白了,这种正则有什么价值么,瞎写的长,缩写一下^(\d{17})([0-9X])$
你看这么简单的东西给你搞那么长,还显得专业,实际上没技术含量。有关身份证的正则,我想到时候再研究一下,然后出一期讲一下。
然后回到小祖宗的需求,a|b|c,abc都只是数字,那么拆分一下,头必须是数字,尾巴也必须是数字。好^[0-9][0-9]$,安排上。中间是一个|b|型的其实不是,因为我们现在的头和尾都是一位数字,万一他需要两位,其实中间还是a|b|c这个形状,只是此时的a和c是0位而已。这种形式可以表示为[0-9]*\|{1}[0-9]* 。这个表达式只有一次,是肯定不可以的,这个时候应该是{0,}表示出现0次以上,他也要有不存在的时候是嘛。组合一下([0-9]*\|{1}[0-9]*)* 然后把这个东西插到刚刚的表达式里去。测试一下,应该是没有问题了。然后开开心心的给小祖宗,顺便给他展示了下,小祖宗跟我说想复杂了,他只要出现两次 | 就好了。。。。。。。心中万马奔腾,只要改一个*改成{2}就好了。
然后重新正视了下之前的思路,发现还是可以优化的,比如[0-9]*他会导致出现0开头的数字,比如01,这很不自然数,那可以用[1-9][0-9]*即可表示除0外的所有自然数,那0怎么办呢。这个时候用到或 像[1-9][0-9]*|0{1} 这个样子非零自然数或0,但是,这样并没有解决问题,0123他照样是可以取一个0出来,不过好在后面跟了限定符号|,变成形如^([1-9][0-9]*|0{1})\| 这个样子就可以满足和这个需求了
然后还有一个问题是数字位数的问题,因为他前后必须是数字,导致这个问题可能是无解的。
接下来说一下身份证的正则。简单研究了一下,身份证是由前面六位地区编码组成,然后是8位的出生年月日,最后再是4位编码。这其中,六位地区编码粗略的看了下,很难精确的搞,要优化无非也是第一位让他在1-6之间这样,为什么是1-6之间,这个去看一下地区编码就可以了解了,后面五位没有什么改动的空间,可选数字太多,搞起来也很累。那就先用^[1-6]\d{5}表示前六位地区码。接下来是出生年月日,这块能搞的就比较多了。我查了一下现在在世的最长寿的人是117岁,日本人。现在是2020年。也就是说现在19世纪的人基本上都没了。所以年份可以定在19,20这样。(19|20)这样就完成了,后面的两位年份可以随便,也可以严谨一点比如(19\d{2})|(20(0|1)\d))。这样表示从1900-2019年出生的,不过这样搞很麻烦了。为了可以顺利用到2100年。直接改成(19|20)\d{2},表示从1900-2099。足够用了。然后是月份1-12月,表示为(0[1-9]) | (1[0-2])。后面的日子就比较头疼,需要把一些日子单独拎出来。写成这样([0-2][1-9])|10|20|30|31 。然后再跟上四位编码\d{3}[0-9Xx]$。现在一段一段都写好了,将他们拼接在一起得出
^[1-6]\d{5} (19|20)\d{2} ((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31) \d{3}[0-9Xx]$
以上就是我得出来的身份证的正则了,至少可以淘汰掉日期不对的身份证。筛选一部分
贴一下元字符的网址,这种百度能搜到的东西我个人不太喜欢背,只要自己了解就好了,要用的时候去找反而更方便,脑子就这么点大。