如何创建可记忆首个分隔符、强制统一分隔符的日期匹配正则表达式
正则实现统一分隔符日期匹配方案
完全可以通过正则的反向引用特性实现需求,同时解决原有正则分隔符可选、分隔符混用的问题。
原有正则的问题
你之前写的正则存在两个不符合预期的点:
- 分隔符用
[-\/]?标记为可选,因此无分隔符的YYYYMMDD、缺单个分隔符的混排格式都会被匹配 - 两个分隔符位置的匹配规则独立,没有做一致性校验,因此
-和/混用的格式也能通过校验
符合要求的正则实现
核心逻辑:
- 把第一个分隔符匹配到的内容(
-或/)存入捕获组 - 第二个分隔符位置通过反向引用直接复用第一个捕获组的匹配结果,强制两个分隔符完全一致
- 去掉分隔符后的
?可选标记,强制要求必须携带分隔符 - 补全年份1900-9999的范围限制(原正则
\d{4}会匹配0000-1899的非法年份) - 增加首尾锚点
^和$,避免字符串中嵌入的日期片段被误判
/** * 匹配带统一分隔符的YYYY-MM-DD/YYYY/MM/DD格式日期 * 校验规则: * - 年份范围:1900-9999 * - 月份范围:01-12 * - 日期范围:01-31 * - 强制携带分隔符,年与月、月与日之间的分隔符必须完全一致(仅支持-、/两种分隔符) * - 不匹配无分隔符、缺分隔符、分隔符混用的非法格式 * @type {RegExp} */ const patternYYYYMMDD = /^(19|[2-9]\d)\d{2}([-\/])(0[1-9]|1[0-2])\2(0[1-9]|[12][0-9]|3[01])$/; // 测试用例(可直接在浏览器控制台运行) const p = (msg) => console.log(msg); p(patternYYYYMMDD.test("20220102")) // 输出 false:无分隔符,不匹配 p(patternYYYYMMDD.test("2022-01-02")) // 输出 true:统一使用-分隔,匹配 p(patternYYYYMMDD.test("2022/01/02")) // 输出 true:统一使用/分隔,匹配 p(patternYYYYMMDD.test("2022/0102")) // 输出 false:缺第二个分隔符,不匹配 p(patternYYYYMMDD.test("202201/02")) // 输出 false:缺第一个分隔符,不匹配 p(patternYYYYMMDD.test("2022/01-02")) // 输出 false:分隔符混用,不匹配 p(patternYYYYMMDD.test("1899-12-31")) // 输出 false:年份小于1900,不匹配
关键语法说明
正则中的\2就是反向引用语法,对应第2个捕获组(也就是第一个分隔符位置匹配到的内容):如果第一个分隔符匹配到-,\2位置就仅允许匹配-;如果第一个分隔符匹配到/,\2位置就仅允许匹配/,从根源上避免分隔符混用的问题。
扩展:同时兼容无分隔符格式
如果需要同时支持无分隔符的YYYYMMDD格式,只需要把无分隔符的匹配规则作为平行分支加入正则即可:
// 同时支持无分隔符YYYYMMDD、统一分隔符的YYYY-MM-DD/YYYY/MM/DD格式 const patternYYYYMMDDFlex = /^(?:(19|[2-9]\d)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])|(19|[2-9]\d)\d{2}([-\/])(0[1-9]|1[0-2])\5(0[1-9]|[12][0-9]|3[01]))$/;
注意这个写法里因为捕获组序号随分支变化,分隔符对应的反向引用调整为\5。
内容的提问来源于stack exchange,提问作者PatS
相关产品推荐
相关产品推荐

