本文中所有示例采用javascript语言编写;
其中变量str一般表示字符串,reo一般表示正则对象,result 一般表示执行结果。
部分示例逻辑并不严谨,仅作为功能演示用;如果需要使用到项目中请自行完善。
一、正则简介
正则表达式(Regular Expression 或 RegExp )
正则表达式,又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
通俗的讲:就是使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。
出现得早
正则表达式的"祖先"可以一直上溯至对人类神经系统如何工作的早期研究。最早可以追溯到1956年一位数学家发表的论文中引入此概念。
在线测试
- regex101
推荐使用,有描述说明
- regexr
- 正则测试-开源中国
- 正则测试-站长工具
- W3Scholl-js在线调试
文中的示例代码全部使用js编写,可在此页面快速运行调试
1. 功能展示
正则表达式可以使用简单的代码完成比较复杂的功能;以下三个示例中间分别使用正则表达式对数据进行提取、验证、替换操作,让你近距离感受正则的魅力所在。
-
正则表达式可以很方便的在字符串中提取我们想要的信息。
示例:
提取字符串str中的所有电话号码。var str = "张三13612345678,李四18712345678,王五13312345678"; var reo = /\d{11}/g; //规则:匹配数字(11位),全局匹配, var result = str.match(reo); //字符串的match()方法 alert(result) //提示:13612345678,18712345678,13312345678
-
正则表达式可以对字符串进行格式验证。
示例:
用户注册的时候,要求输入的用户名可以包含字符、数字、下划线,并设最小长度为6,最大长度为20。var reo= /^\w{6,20}/; //规则:只能已非特殊符号开头,非特殊符号长度6到20位。 alert(reo.test("abc")) //false(长度不够) alert(reo.test("#abcdef")) //false (有特殊符号) alert(reo.test("abcdef_2132")) //true (验证通过)
-
正则表达式可以快速替换字符串中符合规则的内容。
示例:
将字符串str中的手机号码进行脱敏处理,及隐藏中间四位数。var str = "张三13612345678,李四18712345678,王五13312345678"; var reo = /(\d{3})\d{4}(\d{4})/g; //规则:组1,匹配前三位数;组2匹配后四位数 var result = str.replace(reo, '$1****$2');//替换组1和组2中间的四位数为**** alert(result) //提示:张三136****5678,李四187****5678,王五133****5678
2. 使用场景
- 批量提取/替换有规律的字符串
- 用户录入数据的合法性验证
- 模板引擎的标签库开发
- 网络爬虫的数据提取开发
- 批量文本高效处理等
3. 应用广泛
正则表达式可以在多种文本编辑器/办公软件/开发语言中使用。
正则表达式是编程人员的必备技能!
二、主要功能
1. 验证
在做表单数据提交前,我们通常会对用户录入的数据进行基础的格式验证。
比如:
- 只能录入字母或数字(用户名)
- 手机号码验证(用户联系电话)
- 整数验证 (商品数量)
- 身份证号码验证
- 密码强度验证
- 涉黄词语验证
- …
2. 查找
从大量信息中快速提取指定的内容。
比如:
- 从一个txt小说中提取所用的章节标题
- 从一个文章中提取所有的话号码
- …
3. 替换
将指定格式的文本进行正则匹配查找,找到之后进行特定替换。
比如:
- 修改html标签名。
- 对隐私内容进行脱敏操作。
- …
三、学习正则
1. 正则相关方法
在了解正则表达式怎么写之前,先了解一下正则相关的有哪些常用方法。
1.1 创建
- 字面量方式创建
var reo = /\d/;
- 构建函数创建
var reo = new RegExp('\d');
1.2 正则对象方法
正则表达式对象自带exec()和test()两个方法。
exec(str) 检索
检索指定字符串str中第一个符合的值,没有则返回null。
示例:获取字符串str中的第一个数字。
var str = "a9b2c3";
var reo = /\d/; //表达式,匹配数字
alert(reo.exec(str)) //提示:9
test(str) 验证
检测字符串str是否匹配某个规则,返回true/false。
常用对用户录入的内容进行合法性校验。
示例:判断字符串str内容是否为数字。
var str = "a1b2c3";
var reo = /^\d/; //表达式,匹配数字
alert(reo.test(str)) //提示:false
var str = "123";
alert(reo.test(str)) //提示:true
lastIndex 属性
正则开始匹配的起始位置索引。
首先看一个示例,每次test()的结果都不同。
var str = "a1bc";
var reo = /\d/g; //表达式,匹配数字
alert(reo.test(str)) //提示:true
alert(reo.test(str)) //提示:false
alert(reo.test(str)) //提示:true
这是因为每次匹配后,会把lastIndex的索引位置加1,没有匹配到时重置为0。
我们每次验证前手动重置一下即可解决。
var str = "a1bc";
var reo = /\d/g; //表达式,匹配数字
alert(reo.test(str)) //提示:true
reo.lastIndex = 0;
alert(reo.test(str)) //提示:true
reo.lastIndex = 0;
alert(reo.test(str)) //提示:true
全局模式下的exec()可以循环执行匹配所用内容就是使用的lastIndex属性实现的。
var str = "a9b2c3";
var reo = /\d/g; //表达式,匹配数字
var one;
while((one = reo.exec(str))!=null){
alert(one); //依次提示:9;2;3
}
lastIndex 仅对正则对象自带方法有效,对字符串对象的方法是不起作用的!
1.3字符串对象方法
search(reo) 查找
查找字符串中指定规则reo第一次出现的位置,返回位置编码或-1。
示例:获取字符串str中第一个数字出现的位置编码。
var str = "a0b2c3";
var reo = /\d/; //表达式,匹配数字
var ls = str.search(reo); //字符串的search()方法
alert(ls) //提示:1
replace(reo,xxx) 替换
j将字符串中符合指定规则reo的内容替换为xxx,返回替换后的字符串。
示例:将字符串str中的数字替换为逗号。
var str = "a1b2c3";
var reo = /\d/g; //表达式,匹配数字,全局匹配
var ls = str.replace(reo,','); //replace()方法
alert(ls) //提示:a,b,c,
split(reo) 分割
将字符串根据指定规则reo进行分割,返回分割后的数组。
示例:将字符串str根据数字分割。
var str = "a1b2c3";
var reo = /\d/; //表达式,匹配数字
var ls = str.split(reo); //字符串的split()方法
alert(ls) //提示:a,b,c,
match() 匹配
检索字符串中符合指定规则reo的值,没有全局标识时返回第一个值,有全局标识时返回匹配值的数组。
示例:1.获取字符串str中第一个数字;2.获取字符串str中的所有数字。
var str = "a1b2c3";
var reo = /\d/; //表达式,匹配数字
var ls = str.match(reo); //字符串的match()方法
alert(ls) //提示:1
reo = /\d/g; //表达式,匹配数字,全局匹配
ls = str.match(reo); //字符串的match()方法
alert(ls) //提示:1,2,3
2. 表达式的构成
一个复杂的正则规则主要由元字符、限定符、 修饰符、普通字符组成而成。
2.1 元字符
元字符是正则表达式的基础,就好比英语中的字母ABC。
后面用到的正则表达式都依赖于元字符,组合各个元字符和字符串即可完成复杂的正则匹配。
- 基础元字符
符号 | 含义 | 说明 |
---|---|---|
. | 除换行符以外的任意字符 | \n以外的字符 |
\w | 字母或数字或下划线 | 非特殊符号 |
\s | 空白符 | 空格或tab键 |
\d | 数字 | 0到9 |
\b | 单词的开头或结尾 | 前后非字母取中间 |
^ | 开头 | 指定前缀,在[]使用表示取反 |
$ | 结尾 | 指定后缀 |
() | 分组 | 或提升优先级 |
[] | 集合 | 括起来内容全视为普通字符 |
- 运算元字符
符号 | 含义 | 说明 |
---|---|---|
^ | 取反 | |
| | 或者 |
- 反义元字符(大写)
符号 | 含义 | 说明 |
---|---|---|
\W | 匹配特殊符号 | 及非字母或数字或下划线的其他符号 |
\S | 匹配非空白符 | |
\D | 匹配非数字的字符 | |
\B | 匹配单词开头或结束的位置 |
2.2 限定符
也可叫做重复模式,用于标记指定规则的重复次数(长度)。
符号 | 含义 | 说明 |
---|---|---|
? | 0/1 次 | 可有可无 |
* | >=0 次 | 等价于 {0,} |
+ | >=1 次 | 等价于 {1,} |
{n} | n 次 | |
{n,m} | n-m 次 | |
{n,} | >=n 次 |
? 详解
表示指定规则重复匹配0次或1次,当指定内容可有可无时使用。
示例:
普通的1开头的11位数字或使用‘+86’做前缀加1开头的11位数字,我们都认为是正确手机号码格式。
var str ="13612345678";
var reo = /^1\d{10}/; //规则:普通11位的手机号码
alert(reo.test(str)) //提示:true
/*
* 规则:普通11位的手机号码,且可以带有中国地区标识(+86)
* 因为‘+86’是一个整体,需要使用括号括起来
* 然后在括号后面使用‘?’来标记‘+86’可有可无
*/
reo = /^(\+86)?1\d{10}/;
alert(reo.test(true)) //提示:true
str ="+8613612345678";
alert(reo.test(true)) //提示:true
* 详解
当指定内容的重复规则完全不清楚时使用。
示例:
提取指定字符串str内容中,姓名‘张’什么‘峰’的。
var str ="班上有叫张三峰的、张雪峰的,还有叫张喇嘛峰的";
var reo = /张[\u4e00-\u9fa5]*峰/g; //规则:
var result = str.match(reo); //字符串的match()方法
alert(result) //提示:张三峰,张雪峰,张喇嘛峰
+ 详解
标识指定内容重复出现1次及以上。
示例:
获取指定字符串str中的所有英文单词。
var str ="hello world!";
var reo = /\b[a-zA-Z]+\b/; //规则:英文字母出现一次及以上
var result = str.match(reo);
alert(result) //提示:hello,world
{} 详解
动态指定具体的重复规则,可以指定最小和最大值。
示例:
判断用户姓名只接受2到10位。
var str="张三丰";
var reo = /[\u4e00-\u9fa5]{2,10}/; //规则:中文,长度为2到10位
alert(reo.test(str));//提示:true
str = "丰";
alert(reo.test(str));//提示:false
贪婪与懒惰匹配
使用限定符匹配时,会有贪婪和懒惰两种情况,编写规则时需要特别注意。
- 贪婪匹配(默认)
及尽可能多的向后匹配,一直到把整个内容匹配完后再返回结果。 - 懒惰匹配(加‘?’)
及尽可能少的向后匹配,只要发现符合的就立即返回结果。
语法 | 说明 |
---|---|
*? | 重复任意此,但尽可能少重复 |
+? | 重复1次或多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n次或m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
示例:
还是提取指定字符串str内容中,姓名‘张’什么‘峰’的。
//默认贪婪比配时无法正常提取出“张三峰”
var str ="张三峰的要去攀登珠穆朗玛峰";
var reo = /张[\u4e00-\u9fa5]*峰/g; //规则:张什么峰
var result = str.match(reo); //字符串的match()方法
alert(result) //提示:张三峰的要去攀登珠穆朗玛峰
//当我们加入懒惰匹配后就正常多了
reo = /张[\u4e00-\u9fa5]*?峰/g; //规则:张什么峰,中间懒惰比配
result = str.match(reo);
alert(result) //提示:张三峰
2.3 修饰符
修饰符写在结束的/之后,可以影响整个正则表达式的匹配行为。
常见的修饰符如下:
符号 | 含义 | 说明 |
---|---|---|
g | 全局匹配 | 匹配所有项 |
i | 忽略大小写 | 忽略英文字母的大小写 |
x | 忽略空白 | 忽略内容中的空格 |
m | 多行匹配 | 将有换行的内容视为多个值分别比配 |
s | 单行匹配 | 转义回车换行符作为普通字符 |
全局模式
默认只返回第一个匹配项,全局模式返回所有匹配项。
示例:匹配字符串str中的所有数字。
var str = "a1b2c3";
var reo = /\d/; //表达式,匹配数字
alert(str.match(reo)) //提示:1
reo = /\d/g; //全局模式
alert(str.match(reo)) //提示:1,2,3
忽略大小写
在匹配时忽略英文字母的大小写。
示例:匹配字符串str中的所有字母(忽略大小写)。
var str = "A1b2c3";
var reo = /[a-z]/g; //表达式,全局匹配小写字母
alert(str.match(reo)) //提示:b,c
reo = /[a-z]/gi; //全局匹配小写字母,忽略大小写
alert(str.match(reo)) //提示:A,b,c
多行匹配
多行匹配|将有换行的内容视为多个值分别比配。
var str = 'a1b2c3'+'\n'+'321';
var reo = /^\d*$/g; //规则:匹配纯数字
alert(str.match(reo)) //提示:null
reo = /^\d*$/gm; //规则:匹配纯数字,多行匹配
alert(str.match(reo)) //提示:321
2.4 字符集
正则表达式提供一些常用的字符集及其简写, 见下表:
符号 | 简写 | 说明 |
---|---|---|
[0-9] | \d | 数字,0到9 |
[^0-9] | \D | 非数字 |
[a-z] | 小写英文字母 | |
[A-Z] | 大写英文字母 | |
[a-zA-Z] | 大小写英文字母 | |
[a-zA-Z0-9_] | \w | 数字字母下划线 |
[^\W] | \W | 非数值字母下划线 |
[\r\t\n\f] | \s | 空白区域 |
[^\s] | \S | 非空白区域 |
[\u4e00-\u9fa5] | 中文 |
2.5 其他符号
符号 | 含义 | 说明 |
---|---|---|
\f | 换页符 | |
\n | 换行符 | |
\r | 回车符 | |
\t | 制表符 | |
\v | 垂直制表符 | |
\p | CR/LF | 等同于 \r\n |
3. 运算符优先级
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式类似。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。
具体见下表;(优先级从上至下排列)
运算符 | 描述 |
---|---|
\ | 转义符 |
()、(?: )、(?=)、[] | 圆括号和方括号 |
*、 +、?、 {n}、 {n,}、 {n,m} | 限定符 |
^、 $,、\任何元字符、普通字符 | 定位点和序列(即:位置和顺序) |
| | 或 |
四、深入学习
1. 正则规则分组
及对比较复杂的规则进行细分为多个组,每个组实现对应的比配功能。这样及能使规则代码更易读,还能进阶更高大上的功能。最常见的就是对数据脱敏时的前后分组替换中间部分的操作。
以网站域名地址‘https://baidu.com’为例,主要由三部分组成:
- 协议
https对于正则^\w{2,8}:/\/\
- 儿级域名
baidu对应正则\s
- 顶级域名
com
现在我们有一个匹配网站地址的正则:
\w{2,8}:/\/\
对现有正则进行分组:
获取单个分组的内容:
未完待续
var r= /^(\d{4})-(\d{1,2})-(\d{1,2})$/; //正则表达式 匹配出生日期(简单匹配)
r.exec('1985-10-15');
s1=RegExp.$1;
s2=RegExp.$2;
s3=RegExp.$3;
alert(s1+" "+s2+" "+s3)//结果为1985 10 15
五、常用的正则表达式整理
1. 表单验证
- 用户昵称
可包含大小写字母、数字、下划线、中文;不能为空,长度不超过20位。
[A-Za-z0-9_\u4e00-\u9fa5]{1,20}
- 身份证号
18位数的身份证=17位数字+1为数字或X结尾;
或者15位数字(15位的身份证号大多数业务已经禁止使用了)。
\d{17}[\d|x]|\d{15}$
- 手机号码
1开头的11位数字(因为可能有新号段,就不做强匹配了)。
1\d{10}$
- 邮箱地址
已非特殊字符串开头+不定位数的非特殊字符串(含-.+)+'@'+大于一位的字母或数字(含-)+‘.’+2到14位字母或数字
\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
- 网址
已常见网络协议开头接‘://’,不能包含空白符。
^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+
- ip地址
由四段数字组成,每段的值需满足ip对应规则,通过‘.’分割。
(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)
2. 数据脱敏
前端脱敏并不可取,此处只为了展示脱敏方式,实际开发中请采用服务端脱敏。
- 匿名
不显示用户全名,只显示最后一位
var str = "欧阳五爷"; var reo = /.*(.{1})/; //此处计算需要替换的位数 var str1= "*"; var len = str.length; while(len>1){ str1+="*"; len--; } var result = str.replace(reo, str1+'$1'); alert(result) //提示:***爷
- 身份证号
不显示出生日期
var str = "110101199003073650"; var reo = /(\d{6})\d{8}([0-9X]{4})/g; var result = str.replace(reo, '$1********$2'); alert(result) //提示:110101********3650
- 手机号码
不显示中间4位数
var str = "13612345678"; var reo = /(\d{3})\d{4}(\d{4})/g; var result = str.replace(reo, '$1****$2'); alert(result) //提示:136****5678