正则入门
正则 是个难啃的骨头, 以前看着会正则的人 感觉都好牛逼. 于是工作了 2 年了终于鼓起勇气啃这个骨头了..
例子入手
首先我们先看下相关的字符代表. 我们先看这个例子. 这个就是验证字符串是否是数字.
- let regex = /^[0-9]+$/;
- let number = '123';
- let string = 'abc';
- regex.test(number); // true
- regex.test(string); // false
可能很多人这时用到了百度谷歌一下然后复制过去直接用就 OK 了, 但是这样沉淀不到东西, 所以我们来静下心看看这个正则到底什么意思, 首先我们要了解的是相关的
^ : 脱字符, 匹配开头, 在多行匹配中匹配行开头, 有时也表示求反的概念.
$ : 美元符号, 匹配结尾, 在多行匹配中匹配行结尾.
{m,} 表示至少出现 m 次.
{m} 等价于{m,m}, 表示出现 m 次.
+: 等价于{1,}, 表示出现至少一次. 记忆方式: 加号是追加的意思, 得先有一个, 然后才考虑追加.
*: 等价于{0,}, 表示出现任意次, 有可能不出现. 记忆方式: 看看天上的星星, 可能一颗没有, 可能零散有几颗, 可能数也数不过来.
可能这时你有些不理解 [0-9], 其实他等价于 [0123456789] , 在正则里可以缩写所以为 [0-9], 同理 [a-z],[A-Z] 也是同样的道理. 为什么使用正则因为他书写简单, 我们还可以简化, 让我们等下看看接下来的这些字符, 思考下怎么继续简化.
那我们大概能猜到这个意思代表什么了, 从 开头(^) 到 结尾($) 0-9([0-9]) 出现 至少一次 (+) , 所以就很好理解了, 为什么这个是验证数字的想必就能理解了.
接下来我们再来看一些特殊字符:
\d 就是[0-9]. 表示是一位数字. 记忆方式: 其英文是 digit(数字).
\D 就是[^0-9]. 表示除数字外的任意字符.
\w 就是[0-9a-zA-Z_]. 表示数字, 大小写字母和下划线. 记忆方式: w 是 Word 的简写, 也称单词字符.
\W 是[^0-9a-zA-Z_]. 非单词字符.
\s 是[ \t\v\n\r\f]. 表示空白符, 包括空格, 水平制表符, 垂直制表符, 换行符, 回车符, 换页符. 记忆方式: s 是 space character 的首字母.
\S 是[^ \t\v\n\r\f]. 非空白符.
. 就是[^\n\r\u2028\u2029]. 通配符, 表示几乎任意字符. 换行符, 回车符, 行分隔符和段分隔符除外. 记忆方式: 想想省略号... 中的每个点, 都可以理解成占位符, 表示任何类似的东西.
好的我们看到了 \d 其实就是 [0-9], 此时忽然恍然大悟, 原来上面的正则还能简化:
let regex = /^\d+$/; // /^[0-9]+$/;
这时我们大概 已经懂得这个正则代表什么东西了, 之后再出现验证用户输入的是不是数字, 就别再百度了, 分分钟就写出来.
举一反三
我们已经了解之前的这个例子后, 大概能推敲如何实现验证全是字母:
- let regex = /^[a-z]+$/;
- let string = 'abc';
- let number = '123';
- regex.test(number); //false
- regex.test(string);//true
正则是区分大小写字母的, 所以, 我们要验证大写字母的时大概是这样:
- let regex = /^[A-Z]+$/;
- let string = 'abc';
- let STRING = 'ABC'
- let number = '123';
- regex.test(number); //false
- regex.test(string);//false
- regex.test(STRING); //true
好了我们已经反二了, 接下来我们来反三, 即是大写字母又是小写字母, 怎么去写?
let regex = /^[a-zA-Z]+$/
估计到这里我们都已经算入门了, 不是很复杂的正则都可以自己去写了.
考验
接下来我们来看一些常用需求:
正则 验证 手机 .
手机号码是几位, emmmm, 等下我先数数 183 XXX XXX XX , 噗, 11 位, 好吧当我没说. 那我们分析下, 手机号, 首先全部都是数字, 开头第一位一定是 数字 1 , 然后只要满足 11 位就可以了, 我们已经把需求整理清楚了, 如果我们用 JS 去写会怎么写? 我这里随意写一写, 可能有更好的方式
- const isPhone = (number) => {
- // 先判断是不是字符串
- if (typeof number !== 'string' || number.length !== 11 ) {
- return false;
- }
- const isNumber = (x) => isNaN(x*1);
- const mapData = (isFn, number) => {
- for( let i = 0;i < number.length; i+=1) {
- if(isFn(number.charAt(i))){
- return false;
- break;
- } ;
- }
- return true;
- }
- const flag = mapData(isNumber, number)
- // 判断每一位是不是数字
- if(!flag) {
- return false;
- }
- // 判断是不是 1 开头.
- if (number.indexOf('1') !== 0) {
- return false;
- }
- return true;
- }
可见一个 JS 书写是多么麻烦, 也可能是我的解决方式不是很牛逼, 随便写写, 各位有什么好的解决方案也可以给我评论.. 扯远了. 现在我们来看看要是用正则怎么写?
let regex = /^1\d{10}$/;
一行代码搞定. 就是这么简单, 让我们分析一下.
^ 开头匹配
1 开头没毛病
\d 表示 [0-9] 代表必须是数字
{10} 也是 {10, 10} 表示 [0-9]出现 10 次, 加上 1 也就是说 11 位.
$ 结尾匹配没毛病. 以上一行代码就搞定了. 很简便其实分析下也不是很难.
正则 验证 邮箱 .
我就不写什么 JS 的版本了, 有兴趣的同学可以自己尝试写写. 我们看看邮箱的正则应该是有这么几个需求的:
mailto:xxx@xxx.xxx
@ 前需要有任意字符
邮箱 有 @ 符号.
@后有任意字符
要有 .
. 后跟任意字符
let regex = /^\w+@\w+\.\w+/;
简单分析一下:
\w 我们知道是 [0-9a-zA-Z_] 下划线
+ 代表至少出现一次 好比 {1,}
@ 必须需要.
. 这里要注意下, 因为 . 是特殊正则字符, 代表通配符, 我们这里需要的是 "." 字符串, 所以加了 \ 进行转译
补充案例
之前的例子们大概动了一些东西, 让我们再来看几个例子.
匹配 16 进制颜色值
大概是这样:
#ffbbad #Fc01DF #FFF #ffE
写法:
let regex = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
分析:
开头是 #号, 表示一个 16 进制字符, 可以用字符组[0-9a-fA-F]. 然后 {6} 代表 出现 6 次, 这时候你可能有点迷 这个代表什么 稍等引出这个 | 是分支的概念. 再说说后面其实也很好理解 字符组[0-9a-fA-F] 出现 3 次.
| 分支, 其实可以理解为这个是编程中的或, 很容易理解了. 那么, 我们知道或者是惰性的, 一个成立不向下执行, 这里其实也一样.
让我们再来一个案例:
验证 匹配 yyyy-mm-dd : 2018-10-20
正则如下:
var regex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
分析一波:
年 \d{4} [0-9]出现 4 次.
月 共 12 个月, 十位 0 的话就是 [1-9]月, 十位 1 的话就是 [0-2]个月.
日 最多 31 天 , 十位 0 的话就是 [1-9]天, 十位 1, 十位 2 就是[0-9] 3 的话只有 0 或者 1.
结语.
正则是个大工程这里只是一些简单的正则, 比如还有惰性匹配等 我们还没有见到, 在后面的系列中我会慢慢的加入进去. 未完...
来源: https://juejin.im/post/5bc6e4535188255c372f86ac