0

0

系统性学习JS正则表达式

php中世界最好的语言

php中世界最好的语言

发布时间:2018-05-24 15:12:48

|

1571人浏览过

|

来源于php中文网

原创

这次给大家带来系统性学习JS正则表达式,学习JS正则表达式的注意事项有哪些,下面就是实战案例,一起来看一下。

一、正则表达式简介

1、什么是正则表达式

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

简单的说,就是按照某种规则去匹配符合条件的字符串。

2、可视化正则表达式工具

Regexper:https://regexper.com/

二、RegExp对象

实例化RegExp的两种方式。

两种方式定义RegExp对象。

1、字面量

let reg = /[a-z]{3}/gmi;
let reg = /[a-z]{3}/g;
let reg = /[a-z]{3}/m;
let reg = /[a-z]{3}/i;

标志

  • g global 代表全局搜索。如果不添加,搜索到第一个匹配停止。

  • m Multi-Line 代表多行搜索。

  • i ignore case 代表大小写不敏感,默认大小写敏感。

2、构造函数

let reg = new RegExp('\bis\b', 'g');

因为JavaScript字符串属于特殊字符,需要转义。

三、元字符

把元字符当作转义字符。

正则表达式有两种基本字符类型组成。

  • 原义文本字符

  • 元字符

1、原义文本字符

表示原本意义上是什么字符,就是什么字符。

2、元字符

是在正则表达式中有特殊含义的非字母字符。  
* + ? $ ^ . | ( ) { } [ ]

字符 含义
水平制表符
垂直制表符
换行符
回车符
空字符
换页符
cX 控制字符,与X对应的控制字符(Ctrl + X)

类似于转义字符。

四、字符类

表示符合某种特性的字符类别。

使用元字符[]可以构建一个简单的类。  
所谓类是指符合某些特性的对象,一个泛指,而不是某个字符。

例子

表达式[abc]把字符abc归为一类,表达式可以匹配这一类中的任意一个字符。

// replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
'a1b2c3d4e5'.replace(/[abc]/g, '0');  //010203d4e5

字符类取反

我们想要替换不是abc中任意一个字符的字符。

// 元字符 ^ 创建一个 反向类/负向类
'abcdefg'.replace(/[^abc]/g, '0');  //abc0000

五、范围类

匹配这一个范围内的字符。

如果我们想要匹配数字0-9,那么我们可能会这样写[0123456789]。  
如果我们想要匹配26个字母,那么我们可能会这样写[abcdefghijklmnopqrstuvwxyz]。  
这样略显麻烦,所以才会有范围类。

例子

// 替换所有数字
'a1c2d3e4f5'.replace(/[0-9]/g, 'x');  //axcxdxexfx
// 替换所有小写字母
'a1c2d3e4f5'.replace(/[a-z]/g, 'x');  //x1x2x3x4x5
// []组成的类内部是可以连写的。替换所有大小写字母
'a1C2d3E4f5G6'.replace(/[a-zA-Z]/g, '*');  //*1*2*3*4*5*6

疑问

如果我想替换数字,并且连带-符号也一起替换呢?

// 替换所有数字和横杠
'2018-5-21'.replace(/[0-9-]/g, '*');  //*********

六、预定义类

一些已经定义的类,可以直接使用。
字符 等价类 含义
. [^ ] 除了回车、换行之外的所有字符
d [0-9] 数字字符
D [^0-9] 非数字字符
s [ ] 空白符
S [^ ] 非空白符
w [a-zA-Z_0-9] 单词字符(字母、数字、下划线)
W [^a-zA-Z_0-9] 非单词字符

例子

替换一个 ab + 数字 + 任意字符 的字符串

// 写法1
'ab0c'.replace(/ab[0-9][^
]/g, 'TangJinJian');  //TangJianJian
// 写法2
'ab0c'.replace(/abd./g, 'TangJinJian');  //TangJianJian

七、单词边界

字符 含义
^ 以xxx开始(不在中括号内时的含义)
$ 以xxx结束
 单词边界
B 非单词边界

例子

我想替换的字符串,属于那种只在开头出现的。

'YuYan is a boy, YuYan'.replace(/^YuYan/g, 'TangJinJian');  //TangJinJian is a boy, YuYan

我想替换的字符串,属于那种只在结尾出现的。

'YuYan is a boy, YuYan'.replace(/YuYan$/g, 'TangJinJian');  //YuYan is a boy, TangJinJian

单词边界例子。

// 替换所有is为0
'This is a man'.replace(/is/g, '0');  //Th0 0 a man
// 替换所有is前面带有单词边界的字符串
'This is a man'.replace(/is/g, '0');  //This 0 a man
// 替换所有is前面没有单词边界的字符串
'This is a man'.replace(/Bis/g, '0');  //Th0 is a man

八、量词

用来处理连续出现的字符串。
字符 含义
? 出现零次或一次(最多出现一次)
+ 出现一次或多次(至少出现一次)
* 出现零次或多次(任意次)
{n} 出现n次
{n,m} 出现n到m次
{n,} 至少出现n次

我想替换字符串中连续出现10次的数字为*

'1234567890abcd'.replace(/d{10}/, '*');  //*abcd

我想替换字符串中的QQ号码。

'我的QQ是:10000'.replace(/[1-9][0-9]{4,}/, '19216811');  //我的QQ是:19216811

九、贪婪模式

尽可能多的匹配。

有这样的一种场景下的正则表达式,/d{3,6}/该替换3个数字还是6个数字呢,4、5个数字?

// 贪婪模式会尽可能的往多的方面去匹配
'123456789'.replace(/d{3,6}/, 'x');  //x789
'123456789'.replace(/d+/, 'x');  //x
'123456789'.replace(/d{3,}/, 'x');  //x

十、非贪婪模式

尽可能少的匹配。

如果我们想要最低限度的替换呢?

// 非贪婪模式使用 ? 尽可能的往少的方面去匹配
'12345678'.replace(/d{3,6}?/g, 'x');  //xx78
'123456789'.replace(/d{3,6}?/g, 'x');  //xxx

因为有g标志,会匹配这段字符串里所有符合规则的字符串。  
第一个规则/d{3,6}?/g12345678中有两个符合条件的字符串,是123456。所以替换结果是xx78。  
第二个规则/d{3,6}?/g123456789中有三个符合条件的字符串,是123456789。所以替换结果是xxx

十一、分组

括号里的一些规则,分为一组。

我想替换连续出现3次的字母数字

//没有分组的情况下,后面的量词,只是表示匹配3次数字。
'a1b2d3c4'.replace(/[a-z]d{3}/g, '*');  //a1b2d3c4
//有分组的情况下,分组后面的量词,表示符合这个分组里规则的字符串,匹配3次。
'a1b2d3c4'.replace(/([a-z]d){3}/g, '*');  //*c4

1、或

分组里有两种规则,只要满足其中一种即可匹配。

//我想把ijaxxy和ijcdxy都替换成*
'ijabxyijcdxy'.replace(/ij(ab|cd)xy/g, '*');  //**

2、反向引用

可以把分组视为变量,来引用。

//我想把改变年月日之间的分隔符
'2018-5-22'.replace(/(d{4})-(d{1,2})-(d{1,2})/g, '$1/$2/$3');  //2018/5/22
//我想替换日期,并且更改顺序
'2018-5-22'.replace(/(d{4})-(d{1,2})-(d{1,2})/g, '$2/$3/$1');  //5/22/2018

3、忽略分组

忽略掉分组,不捕获分组,只需要在分组内加上?:

// 忽略掉匹配年的分组后,匹配月的分组变成了$1,日的分组变成了$2
'2018-5-22'.replace(/(?:d{4})-(d{1,2})-(d{1,2})/g, '$1/$2/$3');  //5/22/$3

十二、前瞻

正则表达式从文本头部向尾部开始解析,文本尾部方向,称为“前”。  
前瞻就是在正在表达式匹配到规则的时候,向前检查是否符合断言,后顾/后瞻方向相反。  
JavaScript不支持后顾。
符合和不符合特定断言称为肯定/正向匹配和否定/负向匹配。
名称 正则 含义
正向前瞻 exp(?=assert)
负向前瞻 exp(?!assert)
正向后顾 exp(?<=assert) JavaScript不支持
负向后顾 exp(?<!assert) JavaScript不支持

例子

有这样一个单词字符+数字格式的字符串,只要满足这种格式,就把其中的单词字符替换掉。

'a1b2ccdde3'.replace(/w(?=d)/g, '*');  //*1*2ccdd*3

有这样一个单词字符+非数字格式的字符串,只要满足这种格式,就把前面的单词字符替换掉。

'a1b2ccdde3'.replace(/w(?!d)/g, '*');  //a*b*****e*

十三、RegExp对象属性

global是否全文搜索,默认false。  
ignore case是否大小写敏感,默认是false。  
multiline多行搜索,默认值是false。  
lastIndex是当前表达式匹配内容的最后一个字符的下一个位置。  
source正则表达式的文本字符串。

let reg1 = /w/;
let reg2 = /w/gim;
reg1.global;  //false
reg1.ignoreCase;  //false
reg1.multiline;  //false
reg2.global;  //true
reg2.ignoreCase;  //true
reg2.multiline;  //true

十四、RegExp对象方法

1、RegExp.prototype.test()

用来查看正则表达式与指定的字符串是否匹配。返回truefalse
let reg1 = /w/;
reg1.test('a');  //true
reg1.test('*');  //false

加上g标志之后,会有些区别。

let reg1 = /w/g;
// 第一遍
reg1.test('ab');  //true
// 第二遍
reg1.test('ab');  //true
// 第三遍
reg1.test('ab');  //false
// 第四遍
reg1.test('ab');  //true
// 第五遍
reg1.test('ab');  //true
// 第六遍
reg1.test('ab');  //false

实际上这是因为RegExp.lastIndex。每次匹配到之后,lasgIndex会改变。  
lastIndex是正则表达式的一个可读可写的整型属性,用来指定下一次匹配的起始索引。

let reg = /w/g;
// 每次匹配到,就会把lastIndex指向匹配到的字符串后一个字符的索引。
while(reg.test('ab')) {
    console.log(reg.lastIndex);
}
// 1
// 2

reg.lastIndex初始时为0,第一个次匹配到a的时候,reg.lastIndex1。第二次匹配到b的时候,reg.lastIndex2

let reg = /ww/g;
while(reg.test('ab12cd')) {
  console.log(reg.lastIndex);
}
// 2
// 4
// 6

reg.lastIndex初始时为0,第一个次匹配到ab的时候,reg.lastIndex2。第二次匹配到12的时候,reg.lastIndex4。第三次匹配到cd的时候,reg.lastIndex6

let reg = /w/g;
// 匹配不到符合正则的字符串之后,lastIndex会变为0。
while(reg.test('ab')) {
    console.log(reg.lastIndex);
}
console.log(reg.lastIndex);
reg.test('ab');
console.log(reg.lastIndex);
// 1
// 2
// 0
// 1

所以,这就是为什么reg.test('ab')再多次执行之后,返回值为false的原因了。

let reg = /w/g;
reg.lastIndex = 2;
reg.test('ab');  //false

每次匹配的起始位置,是以lastIndex为起始位置的。上述例子,一开始从位置2开始匹配,位置2后面没有符合正则的字符串,所以为false

2、RegExp.prototype.exec()

在一个指定字符串中执行一个搜索匹配。返回一个搜索的结果数组或null

非全局情况

let reg = /d(w)d/;
let ts = '*1a2b3c';
let ret = reg.exec(ts);  //ret是结果数组
// reg.lastIndex肯定是0,因为没有g标志。 没有g标志的情况下,lastIndex被忽略。
console.log(reg.lastIndex + '	' + ret.index + '	' + ret.toString());
console.log(ret);
// 0  1 1a2,a
// ["1a2", "a"]

返回数组是有以下元素组成的:

  • 第一个元素是与正则表达式相匹配的文本。

  • 第二个元素是reg对象的第一个子表达式相匹配的文本(如果有的话)。

  • 第二个元素是reg对象的第二个子表达式相匹配的文本(如果有的话),以此类推。

// 子表达式就是分组。
let reg = /d(w)(w)(w)d/;
let ts = '*1a2b3c';
let ret = reg.exec(ts);
console.log(reg.lastIndex + '	' + ret.index + '	' + ret.toString());
console.log(ret);  //输出结果数组
// 0  1 1a2b3,a,2,b
// ["1a2b3", "a", "2", "b"]

全局情况

let reg = /d(w)(w)(w)d/g;
let ts = '*1abc25def3g';
while(ret = reg.exec(ts)) {
    console.log(reg.lastIndex + '	' + ret.index + '	' + ret.toString());
}
// 6  1 1abc2,a,b,c
// 11 6 5def3,d,e,f

第一次匹配的是1abc21abc2的后一个字符的起始位置是6,所以reg.lastIndex6。  
1abc2的第一个字符的起始位置是1,所以ret.index1

第二次匹配的是5def35def3的后一个字符的起始位置是11,所以reg.lastIndex11。  
5def3的第一个字符的起始位置是6,所以ret.index6

十五、字符串对象方法

1、String.prototype.search()

执行正则表达式和String对象之间的一个搜索匹配。  
方法返回第一个匹配项的index,搜索不到返回-1。  
不执行全局匹配,忽略g标志,并且总是从字符串的开始进行检索。

我想知道Jin字符串的起始位置在哪里。

'TangJinJian'.search('Jin');  //4
'TangJinJian'.search(/Jin/);  //4

search方法,既可以通过字符串,也可以通过正则描述字符串来搜索匹配。

2、String.prototype.match()

当一个字符串与一个正则表达式匹配时, match()方法检索匹配项。  
提供RegExp对象参数是否具有g标志,对结果影响很大。

非全局调用的情况

如果RegExp没有g标志,那么match只能在字符串中,执行一次匹配。  
如果没有找到任何匹配文本,将返回null。  
否则将返回一个数组,其中存放了与它找到的匹配文本有关的信息。

let reg = /d(w)d/;
let ts = '*1a2b3c';
let ret = ts.match(reg);
console.log(ret.index + '	' + reg.lastIndex);
console.log(ret);
// 1  0
// ["1a2", "a"]

非全局情况下和RegExp.prototype.exec()方法的效果是一样的。

全局调用的情况

我想找到所有数字+单词+数字格式的字符串。

let reg = /d(w)d/g;
let ts = '*1a2b3c4e';
let ret = ts.match(reg);
console.log(ret.index + '	' + reg.lastIndex);
console.log(ret);
// undefined  0
// ["1a2", "3c4"]

全局情况下和RegExp.prototype.exec()方法的区别。在于,没有了分组信息。  
如果我们不使用到分组信息,那么使用String.prototype.match()方法,效率要高一些。而且不需要写循环来逐个所有的匹配项获取。

3、String.prototype.split()

使用指定的分隔符字符串将一个String对象分割成字符串数组。
'a,b,c,d'.split(/,/);  //["a", "b", "c", "d"]
'a1b2c3d'.split(/d/);  //["a", "b", "c", "d"]
'a1b-c|d'.split(/[d-|]/);  //["a", "b", "c", "d"]

4、String.prototype.replace()

返回一个由替换值替换一些或所有匹配的模式后的新字符串。模式可以是一个字符串或者一个正则表达式, 替换值可以是一个字符串或者一个每次匹配都要调用的函数。

常规用法

'TangJinJian'.replace('Tang', '');  //JinJian
'TangJinJian'.replace(/Ji/g, '*');  //Tang*n*an

以上两种用法,是最常用的,但是还不能精细化控制。

精细化用法

我想要把a1b2c3d4中的数字都加一,变成a2b3c4d5

'a1b2c3d4'.replace(/d/g, function(match, index, orgin) {
    console.log(index);
    return parseInt(match) + 1;
});
// 1
// 3
// 5
// 7
// a2b3c4d5

回调函数有以下参数:

  • match第一个参数。匹配到的字符串。

  • group第二个参数。分组,如果有n个分组,则以此类推n个group参数,下面两个参数将变为第2+n3+n个参数。没有分组,则没有该参数。

  • index第三个参数。匹配到的字符串第一个字符索引位置。

  • orgin第四个参数。源字符串。

我想把两个数字之间的字母去掉。

'a1b2c3d4e5f6'.replace(/(d)(w)(d)/g, function(match, group1, group2, group3, index, orgin) {
  console.log(match);
  return group1 + group3;
});
// 1b2
// 3d4
// 5f6
// a12c34e56相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

react实现选中li高亮步骤详解

前端中排序算法实例详解

Otter.ai
Otter.ai

一个自动的会议记录和笔记工具,会议内容生成和实时转录

下载

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

46

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

178

2026.03.11

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

51

2026.03.10

Kotlin Android模块化架构与组件化开发实践
Kotlin Android模块化架构与组件化开发实践

本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

92

2026.03.09

JavaScript浏览器渲染机制与前端性能优化实践
JavaScript浏览器渲染机制与前端性能优化实践

本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

102

2026.03.06

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

227

2026.03.05

PHP高性能API设计与Laravel服务架构实践
PHP高性能API设计与Laravel服务架构实践

本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

532

2026.03.04

AI安装教程大全
AI安装教程大全

2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

171

2026.03.04

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 6万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.4万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号