- A+
正则表达式又叫规则表达式,一般用来检查字符串中是否有与规则相匹配的子串,达到可以对匹配的子串进行提取、删除、替换等操作的目的。先了解有哪些方法可以使用正则对字符串来实现这些操作:
RegExpObject.test(string):
检查字符串 string 中是否有与 RegExpObject 匹配。有则返回 true,否则返回 false。
RegExpObject.exec(string):
检索字符串 string 中与 RegExpObject 匹配的值。有则返回相关结果的数组,否则返回 null。
stringObject.search(regexp):
找到字符串 stringObject 中第一个与 regexp 相匹配的子串的位置。
stringObject.match(regexp):
检索字符串 stringObject 中与 regexp 匹配的值;
如果 regexp 没有标志 g,进行非全局检索,执行结果与RegExpObject.exec方法相同;
如果 regexp 有标志 g,进行全局检索,返回 stringObject 中所有匹配的子字符串的数组。
stringObject.replace(regexp,replacement):
在 stringObject 找到与 regexp 匹配的子串,用 replacement 替换,返回新的字符串。
stringObject.split(separator,howmany):
用 separator 为边界,把 stringObject 分成数组,数组长度不能大于 howmany。
正则表达式最简单的规则就是匹配完全相同的普通字符,比如在一个字符串中,需要把一些敏感词用*号代替。声明字符串如下:
var str = '这是1个字符串,包含了我X和垃圾这2个敏感词,而且还是垃圾这个词还有2个,字符串中还包含数字345。';
声明一个简单的正则直接量,然后在上面字符串中匹配到符合规则的子串进行替换:
var reg = /垃圾/; var sResult = str.replace(reg,'**'); //输出结果 console.log(sResult);
输出的结果如图所示:
可以看到第一个 “垃圾” 子字符串被替换成**,而第二个却没有被替换。这是因为在声明正则的时候,只声明了匹配模式(匹配规则),默认只会检索到第一个匹配的子字符串。
有时候还需要给正则表达式添加修饰符,修饰符可以修改检索时匹配的执行方法,正则表达式的修饰符如下:
i - 匹配时不区分大小写
g - 全局匹配,不会在匹配到第一个之后就中止
m - 多行匹配
在刚才的正则表达式上加上修饰符 g ,就可以进行全局匹配,找到字符串中所以符合规则的子字符串进行替换,如下所示:
var str = '这是1个字符串,包含了我X和垃圾这2个敏感词,而且还是垃圾这个词还有2个,字符串中还包含数字345。'; var reg = /垃圾/g; var sResult = str.replace(reg,'**'); //输出结果 console.log(sResult);
效果符合预期,字符串中的敏感词 “垃圾” 都被修改成了 * 号。非常容易,对吧?稍微加点难度,按照字符串上的描述,还有一个敏感词 “我X” 也需要被替换。只需要把正则改一改,使用正则的分枝条件 | 把不同的匹配分隔开,有点类似于 || 运算符。如下所示:
var str = '这是1个字符串,包含了我X和垃圾这2个敏感词,而且还是垃圾这个词还有2个,字符串中还包含数字345。'; var reg = /垃圾|我X/g; var sResult = str.replace(reg,'**'); //输出结果 console.log(sResult);
好了,看到这里正则也算入门了,至少会用了。但如果想用于工作,肯定是远远不够的,在工作中不可能只匹配完全一样的字符。
要匹配各种不同的字符,就需要用到元字符(正则表达式规定的一种特殊代码)。正则表达式的元字符很多网站都列出了详细的表格,我在这里就偷点懒,不一一列出,继续说正则的实例,用到哪个再详细解释。
工作中有时候会拿到一些数据里面有很多空格,来学一个使用正则删除这些空格的小例子,如下所示:
var str = "有时候 我们拿到的 一些数据里面 , 会一有些多 余的空格,我 们一般都需要删除这些 空格。 " var reg = /s/g; var sResult= str.replace(reg,''); //输出结果 console.log(sResult);
完美,字符串中所有的空格都删除了,不管是一个还是多个。通过上面的实例,就可以知道元字符 s 可以匹配任意的空白符。再加上修饰符 g,所以就匹配到了字符串中所有的空格。
跟着我使用实例一个一个做,学起来会非常轻松。再来看一个工作中经常会碰到的例子,需要把字符串中所有的英文字母都删除。正则表达式中没有单独表示英文的元字符,这时候需要用到 [ ] 来表示字符集合,比如 [az] 就可以匹配到 a 和 z 这两个字母。但26个字母都写 [ ] 在里面好像有点多,所以可以用 [a-z] 这样的省写表示所有英文字母。代码如下所示:
var str = '有时候We我们拿到的Some一些数据里面, 会是中文Chinese和英文English在一起,需要删除这些英文。' var reg = /[a-z]/g; var sResult = str.replace(reg,''); //输出结果 console.log(sResult);
结果有点不符合预期,只删除了小写字母,大写字母还是纹丝不动。可以在这里再学两个知识点,一是在字符集合中把大写字母也加上,比如: /[a-zA-Z]/g ;二是多加一个修饰符 i ,可以不区分大小写,比如: /[a-z]/gi 。我就不演示了,读者可以自己试下。
把需求反过来,把所有中文给删除掉。可以在字符集合使用unicode编码的中文编码开始和结束这两个值来匹配中文,比如: /[u4e00-u9fa5]/g。代码如下所示:
var str = '有时候We我们拿到的Some一些数据里面, 会是中文Chinese和英文English在一起,需要删除这些中文。' var reg = /[u4e00-u9fa5]/g; var sResult = str.replace(reg,''); //输出结果 console.log(sResult);
再来看一个替换数字的实例,这次把字符串中的每组数字都替换成 -- 符号,代表数字的元字符是 d ,代码如下所示:
var str = '这些中文123中间,夹杂456着一些789数字,我们1010现在要做的就是把2324这些数字都换成符号'; var reg = /d/g var sResult = str.replace(reg,'--'); //输出结果 console.log(sResult);
看到结果,又和预期有点不一样。现在是每个数字都换成了 -- 符号,而要求是每组数字替换成 -- 符号。所以再学一个新的知识点:限定符(又叫量词)。限定符规定了匹配的重复方式,常用限定符如下所示:
字符 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
学会限定符后,把上一个例子改一改。现在要替换的一组数字且并不知道它的长度,所以加上一个限定符 + (重复一次或更多次)。如下所示:
var str = '这些中文123中间,夹杂456着一些789数字,我们1010现在要做的就是把2324这些数字都换成符号'; var reg = /d+/g var sResult = str.replace(reg,'--'); //输出结果 console.log(sResult);
很好,符合需求,完美完成。
有时候要匹配的字符就是元字符,比如刚才用到的 +,在一个字符串中需要把限定符 + 换成中文 和 字。这时候需要用到字符转义,所谓字符转义就是在元字符前加 来取消这些字符的特殊意义。代码如下:
var str = '这里有一个字符串,有正+反,高+矮,大+小这些反义词,中间的符号需要修改。'; var reg = /+/g; var sResult = str.replace(reg,'和'); //输出结果 console.log(sResult);
再来写一个匹配日期的正则表达式,2020-10-10和2020/2/2都是正确的日期格式。作为初学者,写正则的时候可以先进行分解。比如:
2020-10-10 分解成 “4个数字1个杠1或2个数字1个杠1或2个数字”,即为 /d{4}-d{1,2}-d{1,2}/
2020/2/2 分解成 “4个数字1个斜杠1或2个数字1个斜杠1或2个数字”,即为 /d{4}/d{1,2}/d{1,2}/
这时候出现了两个分支的情况,为了看得更清楚,可以把两个分支都用圆括号 () 括起来,如:/(d{4}-d{1,2}-d{1,2})|(d{4}/d{1,2}/d{1,2})/
var str = '2020-10-10是一个日期格式'; var str2 = '2020/2/2也是一个日期格式'; var reg = /(d{4}-d{1,2}-d{1,2})|(d{4}/d{1,2}/d{1,2})/; //输出结果都是true console.log(reg.test(str)); console.log(reg.test(str2));
这里的圆括号 () 在正则表达式里面起到一个分组的作用。
看到这里,读者已经知道了正则表达式的普通字符、元字符、分枝条件、字符集合、限定符、字符转义和分组这些知识,是时候做一些真正的实例了。
实例1:修改文本框内容时验证金额
来做一个修改文本框内容时验证金额功能,要求格式为数字;保留两位小数点。
具体实现步骤我就不在这里过多描述,可以参考我的另一篇文章 《原生js制作表单验证,基本的表单验证方法》 学习表单验证功能如何制作。本文还是以正则表达式的规则为主要描述内容。
分析本实例的规则也是非常简单,只有三个要求,一是必须是数字;二是必须有小数点;三是小数点后保留两位数字。要求分析完的规则,完成正则如下:
/^d+\.d{2}$/
在这个正则表达式中,要新学两个元字符 ^ 和 $ 。
^ 匹配字符串的开始位置,$ 匹配字符串的结尾位置。
^d 的意思就是必须数字开头;+ 是限定符表示重复一次或多次; \. 表示小数点,因为小数点本身就是元字符,所以前面要多加一个反斜杠;d{2}$ 表示结尾必须是两个数字。
这样分析完,如果还不清楚的话,可以动手完成以下代码自己看下实际效果:
<div class="form_Box"> <dl> <dt>金额:</dt> <dd><input type="text" id="verifyMoney"><span></span></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyMoney'); //在input元素上绑定change事件 eInput.addEventListener('change',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var reg = /^d+.d{2}$/; //获取父级元素 var eParent = this.parentElement; //获取input元素后的span元素,用于存放提示信息 eSpan = eParent.getElementsByTagName('span')[0]; if(reg.test(sValue)){ //span元素上清除提示 eSpan.innerHTML = ''; }else{ //span元素上显示提示 eSpan.innerHTML = '请输入正确的金额格式,保留两位小数点'; } }); </script>
实例2:文本框只能输入数字和小数点
本实例模拟一个价格输入框,只能输入数字和小数点。可以通过正则表达式找到非数字和小数点的内容替换为空字符串来实现。
分析本实例的规则:一是非数字;二是非小数点。正则表达式如下:
/[^d\.]/g
在这个表达式中,又看到一个新的知识点:^ 字符在表达式最前面表示匹配字符串的开始位置,而在方括号中,表示匹配非字符集 [ ] 中的字符。所以正则表达式 /[^d.]/g 将匹配所有非数字和小数点的字符。
可以用此正则表达式找到文本框中匹配的字符替换为空字符串,看起来就像只能输入数字和小数点。具体实现代码如下:
<div class="form_Box"> <dl> <dt>金额:</dt> <dd><input type="text" id="verifyMoney"></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyMoney'); //在input元素上绑定input事件 eInput.addEventListener('input',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var reg = /[^d.]/g; this.value = sValue.replace(reg,''); }); </script>
笔者在这里再贡献一个严格的金额正则表达式,如下所示:
/^0|^.|[^d.]|(?<=.d*).|(?<=.d{2})d/g;
此表达式严格限制输入金额的格式,只能输入数字;不能0开头且后面不是小数点;小数点后最多只能有两位数字;只能有一个小数点;不能小数点开头。可惜有些浏览器不识别,其中还有未提及的知识点,有兴趣的读者可以自己尝试分解。
实例3:身份证号码验证
网页中经常会碰到需要填写身份证号码,提交的时候就应该先验证身份证格式是否正确。看一下身份证号码的编排规则:1-6位数字代表省市区,第一个数字不能是0;7-14位数字表示出生年月日;15-16位数字表示所在地的派出所代码;17位数字表示性别;18位数字是校检码,可以是0-9,也可以是字母X。根据身份证格式写出正则表达式如下:
/^[1-9]d{5}[12]d{3}((0[1-9])|(1[0-2]))(([0|1|2][1-9])|3[0-1])d{3}([0-9]|X)$/;
再来分解表达式:
- ^[1-9]d{5} 表示省市区6个数字,第一个数字不能是0;
- [12]d{3} 表示出生年份4位数字,限定1000-2999年;
- ((0[1-9])|(1[0-2])) 表示出生月份,限定 01 - 12 之间;
- (([0|1|2][1-9])|3[0-1]) 表示出生日期,限定 01 - 31 之间;
- d{3}([0-9]|X)$ 表示最后4位,最后一位可以是数字或X。
具体实现代码如下:
<div class="form_Box"> <dl> <dt>身份证:</dt> <dd><input type="text" id="verifyCard"><span></span></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyCard'); //在input元素上绑定change事件 eInput.addEventListener('change',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var reg = /^[1-9]d{5}[12]d{3}((0[1-9])|(1[0-2]))(([0|1|2][1-9])|3[0-1])d{3}([0-9]|X)$/; //获取父级元素 var eParent = this.parentElement; //获取input元素后的span元素,用于存放提示信息 eSpan = eParent.getElementsByTagName('span')[0]; if(reg.test(sValue)){ //span元素上清除提示 eSpan.innerHTML = ''; }else{ //span元素上显示提示 eSpan.innerHTML = '请输入正确的身份证号码'; } }); </script>
实例4:手机号码验证
来完成一个手机号码输入框的验证。手机号码必须都是数字;限制前3个数字符合手机运营商规则;总长度固定是11个数字。正则表达式如下:
/^(13[0-9]|14[5-8]|15[^4]|16[56]|17[0-9]|18[0-9]|19[189])d{8}$/
分解表达式:
- ^() 表示括号中的分组开头,限制前3个数字符合手机运营商规则;
1.1 13[0-9] 表示130-139开头是正确号码;
1.2 14[5-8] 表示145-148开头是正确号码;
……
1.7 19[189] 表示191,198,199开头是正确号码。 - d{8}$ 表示是8个任意数字结尾。
具体实现代码如下:
<div class="form_Box"> <dl> <dt>手机:</dt> <dd><input type="text" id="verifyPhone"><span></span></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyPhone'); //在input元素上绑定change事件 eInput.addEventListener('change',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var reg = /^(13[0-9]|14[5-8]|15[^4]|16[56]|17[0-9]|18[0-9]|19[189])d{8}$/; //获取父级元素 var eParent = this.parentElement; //获取input元素后的span元素,用于存放提示信息 eSpan = eParent.getElementsByTagName('span')[0]; if(reg.test(sValue)){ //span元素上清除提示 eSpan.innerHTML = ''; }else{ //span元素上显示提示 eSpan.innerHTML = '请输入正确的手机号码'; } }); </script>
实例5:电话号码验证
电话号码的要求会比手机多一些,先整理目前电话号码相关规则:
区号0开头,共3-4个数字;区号可能会用圆括号括起来;区号后面可能直接连接号码,也可能与号码之间有 空格 或 - ;号码是7-8个数字。根据规则写出正则表达式如下:
/^((0d{2,3})|(\ (d{3,4}\)))[-s]?([2-9]d{6,7})$/
分解表达式:
- 分枝 ^((0d{2,3}) 表示区号是3-4个数字,如 020;
- 分枝 ( (d{3,4}))) 表示用圆括号包含区号,如(020);
- [-s]? 表示区号后面可以直接连接号码,也可以有一个空格或一个 - ;
- ([2-9]d{6,7})$ 表示电话号码,不能是0和1开头的7位或8位数字。
具体实现代码如下:
<div class="form_Box"> <dl> <dt>电话:</dt> <dd><input type="text" id="verifyTel"><span></span></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyTel'); //在input元素上绑定change事件 eInput.addEventListener('change',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var reg = /^((0d{2,3})|((d{3,4})))[-s]?([2-9]d{6,7})$/; //获取父级元素 var eParent = this.parentElement; //获取input元素后的span元素,用于存放提示信息 eSpan = eParent.getElementsByTagName('span')[0]; if(reg.test(sValue)){ //span元素上清除提示 eSpan.innerHTML = ''; }else{ //span元素上显示提示 eSpan.innerHTML = '请输入正确的电话号码'; } }); </script>
如果要同时验证手机和电话号码,正则表达式如下:
/(^(13[0-9]|14[5-8]|15[^4]|16[56]|17[0-9]|18[0-9]|19[189])d{8}$)|(^((0d{2,3})|((d{3,4})))[-s]?([2-9]d{6,7})$)/
实例6:邮箱验证
电子邮箱地址是开发中经常需要验证的一种格式,一般邮箱的格式都是:邮箱名 @ 域名 . 域名后缀。
邮箱规则是:邮箱名一般要求字母或数字开头,中间可以包括数字、字母、下划线或杠;域名一般是多个数字、字母、下划线或杠;域名后缀由2-5个字母组成,且可以是1-2个。
知道邮箱的格式和规则之后,可以写出如下正则表达式:
/^[a-zA-Z0-9][w-]{2,19}@[w-]{2,}(.[a-zA-Z]{2,5}){1,2}$/
分解一下表达式:
1. ^[a-zA-Z0-9] 表示邮箱名必须是字母或数字开头;
2. [w-]{2,19} 表示邮箱名可以包含数字、字母、下划线或杠;
3. @ 邮箱分隔符
4. [w-]{2,} 表示域名是2个以上的数字、字母、下划线或杠;
5. (\.[a-zA-Z]{2,5}){1,2}$ 表示结尾是1-2个域名后缀,域名后缀必须是 . 开头。
具体实现代码如下:
<div class="form_Box"> <dl> <dt>邮箱:</dt> <dd><input type="text" id="verifyMail"><span></span></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyMail'); //在input元素上绑定change事件 eInput.addEventListener('change',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var reg = /^[a-zA-Z0-9][w-]{2,19}@[w-]{2,}(.[a-zA-Z]{2,5}){1,2}$/; //获取父级元素 var eParent = this.parentElement; //获取input元素后的span元素,用于存放提示信息 eSpan = eParent.getElementsByTagName('span')[0]; if(reg.test(sValue)){ //span元素上清除提示 eSpan.innerHTML = ''; }else{ //span元素上显示提示 eSpan.innerHTML = '请输入正确的邮箱地址'; } }); </script>
实例7:日期验证
再来完成一个日期输入框的验证,比前面的日期验证的表达式再稍微复杂一点。本实例中设定日期格式为四种:20.02.02、2020-12-12、2020/2/2、2020年10月2日。这四种格式都是有效日期,分析一下表达式规则:年是4位数字;中间的分隔符可以是 . 、 - 、/ 和 汉字 四种;月和日可以是1到2位数字。正则表达式如下。
/^(d{4}|d{2})(-|/|.)d{1,2}2d{1,2}$|^d{4}年d{1,2}月d{1,2}日$/
来分解一下表达式。^(d{4}|d{2})(-|/|.)d{1,2}2d{1,2}$ 是第一个分枝条件,表示20.02.02、2020-12-12、2020/2/2这三种格式。
- ^(d{4}|d{2}) 表示年是4个数字或2个数字开头;
- (-|/|.) 表示年月中间的分隔符可以是 . 、 - 、/ 这三种中的任意一种;
- d{1,2} 表示月是1个或2个数字;
- 2 表示月日中间的分隔符。这是一个新知识点,叫做 后向引用 ,反斜杠后的数字表示和第几个分组相同的匹配。 2 作用是月日之间的分隔符要和年月之间的分隔符(即第2个分组 (-|/|.) )的匹配一致。比如年和月之间用的是 - ,那么月和日之间也必须是 - 分隔,这样可以限制 2020-02/02 就是一个无效的匹配;
- d{1,2}$ 表示日是1个或2个数字。
^d{4}年d{1,2}月d{1,2}日$ 是第二个分枝条件,表示匹配 2020年10月2日 这种格式,读者可以自己分解试试。具体实现代码如下:
<div class="form_Box"> <dl> <dt>日期:</dt> <dd><input type="text" id="verifyDate"><span></span></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyDate'); //在input元素上绑定change事件 eInput.addEventListener('change',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var reg = /^(d{4}|d{2})(-|/|.)d{1,2}2d{1,2}$|^d{4}年d{1,2}月d{1,2}日$/; //获取父级元素 var eParent = this.parentElement; //获取input元素后的span元素,用于存放提示信息 eSpan = eParent.getElementsByTagName('span')[0]; if(reg.test(sValue)){ //span元素上清除提示 eSpan.innerHTML = ''; }else{ //span元素上显示提示 eSpan.innerHTML = '请输入正确日期'; } }); </script>
笔者在这里再贡献一个严谨版的日期正则表达式,如下所示:
/^d{4}(-|/|.)(?:(?:0[1-9]|1[0-2])1(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])1(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)(-|/|.)(?:02)2(?:29)$/
此表达式限制格式只能是2020.12.02、2020-12-12、2020/02/02三种;年只能是4位数字,月和日必须是2位数字;月不能超过12;2月闰年才能有29。其中还有未提及的知识点,读者可以复制使用也可以尝试分解。
实例8:密码强度校验
先定义一下密码的要求:密码必须是6-16个字符;纯数字或纯字母强度为低;同时包含字母、数字、特殊符号中的两种为中;同时包含字母、数字和特殊符号为高。
声明三个正则变量,代表不同的强度,通过逻辑运算得出密码强度。三个正则如下所示:
var weakReg = /^[w!@#$%^&*?()]{6,16}$/; var midReg = /^(((?=.*d)(?=.*[!@#$%^&*?()_-]))|((?=.*d)(?=.*[a-zA-Z]))|((?=.*[!@#$%^&*?()_-])(?=.*[a-zA-Z])))[w!@#$%^&*?()]{6,16}$/; var strongReg = /^(?=.*d)(?=.*[a-zA-Z])(?=.*[!@#$%^&*?()_-])[w!@#$%^&*?()]{6,16}$/;
这段正则我就不在此文进行分解,因为涉及的知识点暂时还没说,可能又得多举两个例子,下次有空再在另外的正则文章中叙述。
具体实现代码如下:
<div class="form_Box"> <dl> <dt>密码:</dt> <dd><input type="password" id="verifyPwd"><span></span></dd> </dl> </div> <script> //获取input元素 var eInput = document.getElementById('verifyPwd'); //在input元素上绑定input事件 eInput.addEventListener('input',function(event){ //获取输入值 var sValue = this.value; //声明正则表达式 var weakReg = /^[w!@#$%^&*?()]{6,16}$/; var midReg = /^(((?=.*d)(?=.*[!@#$%^&*?()_-]))|((?=.*d)(?=.*[a-zA-Z]))|((?=.*[!@#$%^&*?()_-])(?=.*[a-zA-Z])))[w!@#$%^&*?()]{6,16}$/; var strongReg = /^(?=.*d)(?=.*[a-zA-Z])(?=.*[!@#$%^&*?()_-])[w!@#$%^&*?()]{6,16}$/; //获取父级元素 var eParent = this.parentElement; //获取input元素后的span元素,用于存放提示信息 eSpan = eParent.getElementsByTagName('span')[0]; eSpan.innerHTML = fnPower(sValue,strongReg,'强') || fnPower(sValue,midReg,'中') || fnPower(sValue,weakReg,'弱') || '密码必须是6-16个字符'; }); //校验密码强度 function fnPower(str,reg,text){ if(reg.test(str)){ return text; }{ return null; } } </script>
例9:经典日期对象格式化
这里有很经典的一个格式化日期时间的方法,多年以前用的人应该非常多。现在不提倡修改原生对象的原型,所以用的人比较少了。代码如下:
Date.prototype.format = function(format){ var o = { "M+" : this.getMonth()+1, //month "d+" : this.getDate(), //day "h+" : this.getHours(), //hour "m+" : this.getMinutes(), //minute "s+" : this.getSeconds(), //second "q+" : Math.floor((this.getMonth()+3)/3), //quarter "S" : this.getMilliseconds() //millisecond }; if(/(y+)/.test(format)){ format = format.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); } for(var k in o) { if(new RegExp("("+ k +")").test(format)){ format = format.replace(RegExp.$1, RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length)); } } return format; }; //获取日期对象 var dToday = new Date(); //输出当前日期与时间,'yyyy-MM-dd hh:mm:ss'中间的分隔符可以随意修改 console.log(dToday.format('yyyy-MM-dd hh:mm:ss'));
在此实例中,传入格式化的字符串 yyyy-MM-dd hh:mm:ss,y 表示年,M 表示月,d 表示日期,h 表示小时,m 表示分,s 表示秒;重复次数表示显示的位数,yyyy 表示年显示为2020(yy显示20),MM 表示月显示为 04(M显示4)。- 和 : 是分隔符,可以修改。
这些字母能在日期对象中能替换成正确的日期时间,因为在对象 o 里面,每一个字母都对应了相对获取日期和时间的方法。如下代码段:
var o = { "M+" : this.getMonth()+1, //month "d+" : this.getDate(), //day "h+" : this.getHours(), //hour "m+" : this.getMinutes(), //minute "s+" : this.getSeconds(), //second "q+" : Math.floor((this.getMonth()+3)/3), //quarter "S" : this.getMilliseconds() //millisecond };
下面这段代码通过 if 条件语句判断正则 /(y+)/ 在字符串中是否存在。如果存在,替换符合正则的字符串部分。
if(/(y+)/.test(format)){ format = format.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)); }
这里有用到一个新知识点 RegExp.$1。RegExp 是正则表达式对象,它有 RegExp.$1 - RegExp.$99 这99个分组匹配属性,和实例7中说过的后向引用是相同概念。RegExp.$1 就是引用第一个分组相同的匹配。
所以 format.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length)) 中的 RegExp.$1 表示 (y+) 这一个分组的正则,即找到 yyyy。(this.getFullYear()+"").substr(4 - RegExp.$1.length) 表示日期对象获取的年份,根据yyyy的长度取值。
下面的循环语句类型,也是通过 RegExp.$1 引用对应正则的字符串,从对象 o 中通过new RegExp创建正则,获取日期对象对应的值。
for(var k in o) { if(new RegExp("("+ k +")").test(format)){ format = format.replace(RegExp.$1, RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length)); } }
比如 o 对象中第一个 "M+",创建的正则是 RegExp("(M+)"),即直接量的 /(M+)/。所以可以通过 this.getMonth()+1 获取月份替换字符串中的 MM。后面的以此类推。
写到这里,正则还有捕获、零宽代言、贪婪和懒惰特性等内容没有描述,我将放到下一篇关于正则的文章再来讲解。同时博客中有些知识描述得也不那么清晰,还请读者多多包涵。