八千字带你进入正则表达式的世界, 使用少量的代码完成数据验证/提取/替换等操作

本文中所有示例采用javascript语言编写;
其中变量str一般表示字符串,reo一般表示正则对象,result 一般表示执行结果。
部分示例逻辑并不严谨,仅作为功能演示用;如果需要使用到项目中请自行完善。

一、正则简介


正则表达式(Regular Expression 或 RegExp )
正则表达式,又称规则表达式,通常被用来检索、替换那些符合某个模式(规则)的文本。
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
通俗的讲:就是使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。

出现得早
正则表达式的"祖先"可以一直上溯至对人类神经系统如何工作的早期研究。最早可以追溯到1956年一位数学家发表的论文中引入此概念。

在线测试

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垂直制表符
\pCR/LF等同于 \r\n

3. 运算符优先级

正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式类似。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。
具体见下表;(优先级从上至下排列)

运算符描述
\转义符
()、(?: )、(?=)、[]圆括号和方括号
*、 +、?、 {n}、 {n,}、 {n,m}限定符
^、 $,、\任何元字符、普通字符定位点和序列(即:位置和顺序)
|

四、深入学习

1. 正则规则分组

及对比较复杂的规则进行细分为多个组,每个组实现对应的比配功能。这样及能使规则代码更易读,还能进阶更高大上的功能。最常见的就是对数据脱敏时的前后分组替换中间部分的操作。

以网站域名地址‘https://baidu.com’为例,主要由三部分组成:

  1. 协议https对于正则^\w{2,8}:/\/\
  2. 儿级域名baidu对应正则\s
  3. 顶级域名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
    
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值