简言
在表单验证中, 经常会用正则表达式做出生日期校验本文把出生日期分割成几个部分, 分步地介绍了实现一个出生日期校验的完整过程相信您在理解了本篇的内容后, 对编写正则表达式会有更深入的理解和更强的信心
出生日期的正则表达式
我们将一个形式如 2018-06-15 的出生日期分割个年份, 月份和日期三个组成部分, 分别来编写相应的正则
1 年份正则
首先给出年份正则表达式的规则定义:
年份由 4 位数字组成
只接受 19,20 开头的年份
根据以上规则, 很容易写出年份的正则表达式:
- var pattern = /^(19|20)\d{2}$/;
- // 输出 true
- console.log(pattern.test("2008"));
其中 $ 两个斜杠及其中间的字符是正则表达式直接量的定义;^ 表示匹配字符串的开头,$ 表示匹配字符串的结尾;^(19|20)表示匹配以 19 或 20 开头的字符串, 一对小括号作用是将几项组合为一个单元; 而 \ d{2}表示匹配任意 ASCII 数字 2 次,\d 等价于 [0-9], 而{2} 则表示匹配前一项 2 次
上述正则表达式可以匹配 1900 至 2099 这些年份, 如果想限制年份的范围, 增加规则如下:
年份起始于 1920 年
年份终止于 2018 年
根据以上规则, 变更正则表达式如下:
- var pattern = /^(19[2-9]\d{1})|(20[01][0-8])$/;
- // 输出 false
- console.log(pattern.test("1916"));
- // 输出 true
- console.log(pattern.test("2008"));
- // 输出 false
- console.log(pattern.test("2022"));
演示代码
2 月份正则
首先给出月份正则表达式的规则定义:
月份可以是 1-12
月份如果是 1-9, 则前面可加 0
根据以上规则, 给出如下正则及简单测试:
- var pattern = /^((0?[1-9])|(1[0-2]))$/;
- // 输出 false
- console.log(pattern.test("19"));
- // 输出 true
- console.log(pattern.test("02"));
- // 输出 true
- console.log(pattern.test("2"));
- // 输出 true
- console.log(pattern.test("11"));
演示代码
3 日期正则
首先给出日期正则表达式的规则定义:
日期可以是 1-31
如果日期是 1-9, 则前面可加 0
根据以上规则, 给出如下正则及简单测试:
- var pattern = /^((0?[1-9])|([1-2][0-9])|30|31)$/;
- // 输出 false
- console.log(pattern.test("32"));
- // 输出 true
- console.log(pattern.test("02"));
- // 输出 true
- console.log(pattern.test("2"));
演示代码
4 组合校验
根据上述的年份正则, 月份正则, 日期正则组合形成出生日期的正则表达式:
- var pattern = /^((19[2-9]\d{1})|(20[01][0-8]))\-((0?[1-9])|(1[0-2]))\-((0?[1-9])|([1-2][0-9])|30|31)$/;
- // 输出 true
- console.log(pattern.test("1923-3-18"));
- // 输出 true
- console.log(pattern.test("1923-4-31"));
- // 输出 true
- console.log(pattern.test("1923-2-29"));
- // 输出 true
- console.log(pattern.test("2016-2-29"));
演示代码
从以上测试结果可以看出, 上述正则验证还不完善, 主要是 2,4,6,9,11 月份的天数问题
5 完善
根据第 4 步的问题, 增加限定规则如下:
4,6,9,11 月没有 31 日
2 月平年是 28 天
2 月闰年是 29 天
平年闰年判定:
能被 4 整除的年份是闰年, 不能被 4 整除的年份是平年但是如果是整百年, 就只有能被 400 整除才是闰年, 否则就是平年
根据新增规则及说明, 给出下面正则函数及测试:
- var checkBirth = function (val) {
- var pattern = /^((?:19[2-9]\d{1})|(?:20[01][0-8]))\-((?:0?[1-9])|(?:1[0-2]))\-((?:0?[1-9])|(?:[1-2][0-9])|30|31)$/;
- var result = val.match(pattern);
- if(result != null) {
- var iYear = parseInt(result[1]);
- var month = result[2];
- var date = result[3];
- if(/^((0?[469])|11)$/.test(month) &&date == '31') {
- return false;
- } else if(parseInt(month) == 2){
- if((iYear % 4 ==0 && iYear % 100 != 0) || (iYear % 400 == 0)) {
- if(date == '29') {
- return true;
- }
- }
- if(parseInt(date)> 28) {
- return false;
- }
- }
- return true;
- }
- return false;
- }
- // 输出 true
- console.log(checkBirth("1923-3-18"));
- // 输出 false 4 月份没有 31 日
- console.log(checkBirth("1923-4-31"));
- // 输出 false 平年
- console.log(checkBirth("1923-2-29"));
- // 输出 true 闰年
- console.log(checkBirth("2016-2-29"));
演示代码
上述正则表达式中利用了 String 的 match()方法, 该方法唯一参数是一个正则表达式, 返回的是一个由匹配结果组成的数组数组的第一个元素就是匹配的字符串, 余下的元素则是正则表达式中用圆括号括起来的子表达式而 (:?...) 这种形式多次出现, 该种方式表示只是把项组合到一个单元, 但不记忆与该组相匹配的字符利用该种方法按照正则匹配的顺序分别取出了年月日项, 以便后序比较
根据上述分析与测试, 我们不但实现了年月日的正则的一般判定, 还实现了日期范围及 2,4,6,9,11 月等特殊月份天数的处理, 测验结果达到了我们设定的目标
根据上述讲解和分析, 我们可以调整相应的限定规则, 使其满足于特定场景下的项目需要
原文链接
来源: http://www.jianshu.com/p/123ef159f88a