2

前言

平时的工作中有很多地方都要用到正则表达式,不得不说,正则的表达式非常强大,比如,我们常用的jquery选择器,非常方便,jquery的源码中,选择器部分应用了大量的正则表达式。然而很多时候,当我们要用到正则的时候,很多人(也包括我 == ) 的做法都是打开百度,复制粘贴,试一下,没问题,大功告成。然而,当遇到特殊需求的时候,复制粘贴大法就不好用了,所以掌握这正则还是很有必要的。下面我就结合我的一些认识对正则进行简单的介绍,如有纰漏欢迎指出。

开胃小菜

假如有这样一道题目:

请写一个邮箱验证的正则。

如果你能写出:

    /@/

试一下:

var reg = /@/;
reg.test("xxx001@pingan.com.cn");//true

图示:

clipboard.png

没毛病!
恭喜你,你已经会写正则了~ (滑稽脸)

其实这是阿里的一道技术面试题,可以写的很简单,也可以写的很复杂,至于写出来的是什么样,就要看个人功力了。

继续往下走。说到邮箱格式,我们简单分析下:

邮箱的命名方式一般分为三部分

  1. 邮件地址

  2. @

  3. 邮箱域名地址

邮件地址部分的规则如下:

  • 英文字母

  • 数字

  • 下划线

  • 中划线

举几个栗子:

  1. 123456@xxx.xxx

  2. blue.sky@xxx.xxx

  3. 123bird@xxx.xxx

  4. ex-xxx001@xxx.xxx

根据以上规则,我们先写一下邮件地址部分:

var reg = /^\w+([-+_.]\w+)*$/;

    reg.test("123456"); //true
    reg.test("blue.sky"); //true
    reg.test("123bird"); //true
    reg.test("ex-xxx001"); //true

图示:

clipboard.png

没什么问题, 继续往下走。

@ 直接用@匹配就可以了

域名地址部分的规则:

  • 英文字母

  • 数字

  • 中划线

@后面的第一个字符不能是中华线和点,简单写一下:

var reg=  /^@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
var reg = /^@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
reg.test("@123-abc.com.cn"); // true

最终的正则可以是这样子的:


var reg = /^\w+([-+_.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
reg.test("scau_kk@xxx.com.cn"); //true

图示:

clipboard.png

到这里,一种简单的邮箱正则就写好了(zz,罗里吧嗦一大堆)。

后面就简单的总结下。

正式入门

字符类

首先介绍下最常见的,也是最基本的 -字符类 。

代码 说明 其它介绍
. 匹配除了换行符之外的任何单个字符 举个例子,在一条句子中, 'nay, an apple is on the tree', .n 可以匹配anon,但是不能匹配nay ;要注意的是:一个未被转义的 . 会匹配除行结束符意以外的任何字符。
^ 匹配字符串的开始
$ 匹配字符串的结束 等同于[0-9]; 一个未转义的$匹配文本的结束。当指定了m标示时,它也能匹配行结束符。
\ 转义字符 可以使用 来取消某些字符本身的意义,比如要想匹配.,* 可以使用 转义字符。 另外,\1 是指向分组1所捕获的文本的一个引用,所以它能被再次匹配。
\b 匹配单词边界 字符边界是一个位置,它的前后都没有其他字符,不过匹配的单词边界并不包含在匹配中。换句话说,匹配字边界的长度为零。
\s 匹配单个空白字符 包括空格、制表符、换行符、换行符。
\S \s 的反义,匹配空白以外的单个字符。
\w 匹配任何字母数字字符包括下划线。 等同于[A-Za-z0-9_]
\W 匹配任何非字符。 等同于[^A-Za-z0-9_]
\d 匹配数字字符 等同于[0-9]
\D 匹配非数字字符 等同于[^0-9]

对照着这个表格,上面的邮箱正则就很容易看了。

举几个简单的例子

console.log(/^\w+$/.test("abc"));  //true
console.log(/^\d+$/.test("12345")); //true
console.log(/^\D+$/.test(" "));  //true

标示

代码 含义 用法
g global, 全局的 如果标示 g 被使用,值为true
i ignore, 大小写不敏感 如果标示 i 被使用,值为true
m multiLine, 多行查找( ^$能匹配行结束符 ) 如果标示 m 被使用,值为true

正则表达式量词

一般用来指定数量,常用的如下所示:

代码 说明
重复零次或更多次
重复1次或更多次
重复0次或更多次
{n} 重复n次
{n,} 重复大于等于n次
{n,m} 重复n到m次

举几个简单的例子

console.log(/^\w{3}$/.test("abc"));  //true
console.log(/^\d{1,5}$/.test("12345")); //true

分支条件

正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配。
具体方法是用|把不同的规则分隔开。

我们来看看个具体的例子:

var reg =  /0\d{2}-\d{8}|0\d{3}-\d{7}/;

这个表达式能匹配两种以连字号分隔的电话号码:

一种是3位区号,8位本地号(如010-12345678),
一种是4位区号,7位本地号(0755-1234567)。

或者写一个简单的匹配手机号码的正则:

var reg =  /^1(3|4|5|7|8)[0-9]\d{8}$/;

分组

我们已经知道了如何重复单个字符,但如果想要重复多个字符又该怎么办呢?
这时候就可以使用分组了。

分组的类型有四种:

代码 用法 介绍
捕获型 () 一个捕获刑分组是一个被包围在圆括号里的正则表达式分支,任何匹配这个分组的字符都会被捕获。每个捕获型分组都被指定了一个数字。在正则表达式中第一个捕获的(是分组1,第二个捕获(的是是分组2。
非捕获型 (?:前缀) 非捕获型分组仅做简单的匹配,并不会捕获匹配的文本。
向前正向匹配 (?=前缀) 向前正向匹配类似于非捕获型分组,但在这个组匹配之后,文本会倒回到它开始的地方,实际上并不匹配任何东西。
向前负向匹配 (?!前缀) 向前负向匹配类似于向前正向匹配分组,但只有当它匹配失败的时候才继续向前进行匹配。

举个简单的例子:

实现一个验证ip地址的正则:

var reg = /^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/;

reg.test("127.0.0.1"); // true
reg.test("255.255.888.888"); // false

结合图示:

clipboard.png

集合图示就很清晰了。

上面的部分只是正则表达式很小的一部分,篇幅有限,下一篇再做介绍。
那根据上面出现的内容,我们看一个更复杂的例子来巩固,摘自精粹,一起来看下。

一个复杂的例子

var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

var  result = parse_url.exec(url);

names.forEach(function(item, index){ 
    console.log(item + ": " + result[index]);
});

console.log(result);
 // url: http://www.ora.com:80/goodparts?q#fragement
 // scheme: http
 // slash: //
 // host: www.ora.com
 // port: 80
 // path: goodparts
 // query: q
 // hash: fragement
 

是不是感觉萌萌哒(滑稽脸.jpg)

看看图:

clipboard.png

我们来分解下parse_url,看它到底是怎么工作的。

首先是 ^, 表示字符串的开始。它是一个锚,指引exec不要跳过那些不像url的前缀,只匹配那些从开头就像url一样的字符串。

scheme


var reg = (?:([A-Za-z]+):)

clipboard.png

这个因子匹配一个协议名,当且仅当后面跟随一个:的时候才匹配。

(?...) 表示一个非捕获型分组。
后缀? 表示这个分组是可选的。

第一个捕获型分组的编号是1,所以该匹配的结果会出现在result[1]中。

slash


var reg = (\/{0,3});

clipboard.png

下一个因子是捕获刑分组2,这里需要对 / 进行转义,这样就不会被解释为结束符。
{0,3}表示 斜杠 / 会被匹配 0次 或者1~3次。

host


var reg = ([0-9.\-A-Za-z]+);

clipboard.png

这第三个捕获型分组是是主机名. 由 一个或多个数字,字母, ., - 组成.
这里需要对-进行转义。

port


var reg = (::(\d+))?;

clipboard.png

这第四个捕获型分组是端口号。它是由一个前置:加上一个或多个数字而组成的序列。

path


var reg = (?:\/([^?#]*))?;

clipboard.png

这个是另一个可选的分组,以一个/`开始。之后的字符类[^?#] 以一个^ 开始,表示这个类包含除? # 之外的所有字符。*表示匹配0次 或多次。

query


var reg = (?:\?([^#]*))?;

clipboard.png

这个还是一个可选分组,以一个?`开始,它包含了一个捕获型分组,这个分组包含 0个 或多个 非 #的字符。

hash


var reg = (?:#(.*))?;

clipboard.png

这是最后一个可选分组,以一个#`开始, . 会匹配除换行符以外的所有字符。

最后的$表示字符串的结束,它保证这个url的尾部没有其他更多内容了。

以上便是parse_url的所有因子了。

这个正则表达式还可以写的更复杂,但通常不推荐这么做。

再举个例子:

var url = "http://www.ora.com:80/goodparts?q#fragement";
 var result = url.split(/^(([^:\/?#]+):)?((\/\/)?([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/);
 console.log(result);

短小精悍的正则表达式是最好的。

作为基础入门的介绍,写到这里就差不多了,后续内容后续会继续发布。

本大汪差不多也该收拾东西,明天回家~预祝大家?年大吉。

附文中出现的可视化工具


皮小蛋
8k 声望12.8k 粉丝

积跬步,至千里。