欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

对于正则表达式的一些整理

程序员文章站 2024-02-16 13:08:16
...

对于正则表达式,以前开发都靠强大的百度。论正则的规矩,看见奇怪的符号,每每不让人选择放弃。之所以学习,是发现找到一个合适的正则是多么难的一件事,若要在人家的基础上去修改,却又看不懂这些个火星文,不得不感叹,还是自食其力的好。

本篇文章是笔者对于正则表达式学习的整理,适合与笔者一样,刚刚认真去学习正则表达式的人,若有较熟悉者,欢迎指正。

一、字符串组成类型
正则表达式由两种字符类型组成:

  1. 原义文本字符
  2. 元字符

原义文本字符。类似于像abc,123
元字符。在正则表达式中有特殊含义的非字母字符,类似于 /b

用的都比较特殊的,例如* + ? $ ^ . | \ () {} [],可以通过下图查找。
菜鸟教程还蛮详细的:https://www.runoob.com/regexp/regexp-metachar.html
对于正则表达式的一些整理
这里说说我试的几个。
(1) [ ] 用来构建一个简单的类
比如说,/[abc]/g,这种属于一类,相当于或的关系,只要是满足了其中一个条件,即触发相应的操作。
如果用这个正则表达式去匹配
eg: ‘He is a boy. This is a dog. where is she’.replace(/[abc]/g, ‘AB’);
// “He is AB ABoy. This is AB dog. where is she”

(2)^ ,一般是指[^ ] 用来创建反向类/负向类****
仍然是上面那个例子,加 ^变成了
eg: ‘He is a boy. This is a dog. where is she’.replace(/[^abc]/g, ‘AB’);
// “ABABABABABABaABbABABABABABABABABABABABABaABABABABABABABABABABABABABABABABABAB”

范围类:当我们说要匹配一个类的时候,比如说A-Z的26个字母,可以使用[A-Z]来连接两个字符表示从a到z的任意字符。
[] 组成的类内部是可以连写的 比如 /[a-zA-Z]/g;
比如想匹配数字和横线,或斜线 [a-z]表示一个范围,但是如果想匹配-,直接在[0-9-]加一个"-"就好了。

(3) 预定义类
个人感觉到这像是一个语法糖,可以根据自己的所需去匹配所有希望匹配的字符串。
对于正则表达式的一些整理
根据图上的符号,我们可以匹配合适的字符串
例如:匹配一个 ab + 数字 + 任意字符的 字符串
这个可以自己去匹配查找对应的一些预定义类
/ab\d./
‘He is a boy. This is a dog. ab993, qe’.replace(/ab\d./, ‘帅’);
// “He is a boy. This is a dog. 帅3, qe”

(4)边界
还是相当于预定义类,只是规定了何时开始,何时结束,用来约束当某一个条件时,才触发相应的规则。
eg;‘This is a boy’.replace(/is/g, ‘0’)
// Th0 0 a boy
‘This is a boy’.replace(/\bis\b/g, ‘0’)
// This 0 a boy
‘This is a boy’.replace(/\Bis\b/g, ‘0’)
// Th0 is a boy

还有的元字符,并不只有一个意思,在特定的内容中代表不同的含义。
比如 * ,是以xxxx开始,而 $ 是以xxx结束。 还有 \B与\b
‘@aaa@qq.com@’.replace(/@./g, ‘Q’);
//aaa@qq.com aaa@qq.com后匹配任意字符
‘@aaa@qq.com@’.replace(/^@./g, ‘Q’);
//“aaa@qq.com@” --以@开头的字符串
‘@aaa@qq.com@’.replace(/aaa@qq.com/g,Q);//"@123@abcQ"/g, 'Q'); //"@aaa@qq.com" --以xx结束

还有类似m,是用来处理换行的
比如
"X23
@456
@789
"
/^@\d/gm/ 后缀加个m,就是用来处理换行的

(5) 量词
对于正则表达式的一些整理
比如说,我们希望匹配一个连续出现20次数字的字符串
\d\d\d\d…这样连续写20遍显然很变态,于是就出现了,专门的量词,来匹配符合条件的字符串
一般的使用场景,会去匹配输入了多少次,限制表单的大小。
? + * {n} {n,m} {n,}

(6) 贪婪模式
尽可能多的匹配,如果匹配失败了再记性后续的操作。
‘12345678’.replace(/\d{3,6}/g, ‘X’);
// “X78”

(7) 非贪婪模式
尽可能少的少用,如果匹配成功了就不继续了
知识的关键点: 在量词后面加?

好了,到了后面已经稍稍加深了。从这里起,我就分为了第二部分,毕竟逻辑已经渐渐加深了。

二、带有逻辑的正则
(1) 分组
场景:匹配字符串repeat连续出现3次的场景
比如这么写 repeat{3} 但是呢,这个意思是说,t出现3次
使用()可以达到分组的功能,是量词作用于分组
比如’a1b2c3d4’
满足字母加数字出现三次的,就触发条件
‘a1b2c3d4’.replace(/([a-z]\d){3}/g, ‘x’);
// xd4

(2)或
使用 | 达到效果
ti(ng|ti)ng
‘tingting’.replace(/ting|ting/g, ‘X’);
// XX
如果只想要局部换,那么
‘tingting’.replace(/tin(g|t)ing/g, ‘X’);

(3)反向引用
比如说,要把年月日2016-11-25替换成11/23/2016
我能想到的,就是用正则表达式把他给匹配出来。
比如说:/\d{4}-\d{2}-\d{2}/g,这其实是第一步,把表达式按正向理出来,可是有一个问题,我们不知道后缀如何替换,也就是
我们并不能动态获取,2016,11,25具体是哪年,哪月,哪日。
这是时候学会了一个东西就是 $ 符号,$符合配合()分组,可以捕获()里的内容
‘2018-03-02’.replace(/(\d{4})-(\d{2})-(\d{2})/g, ‘$2/$3/$1’);
//“03/02/2018”

(4)忽略分组
不希望捕获某些分组,只需要在分组内加上 ?:就可以

(5)前瞻后顾
正则表达式从文本头部向尾部开始解析,文本尾部方向,则是"前"
前瞻就是在正则表达式匹配到规则的时候,向前检查是否符合断言,后顾/前瞻方向相反
但是js不支持后顾
符合和不符合特定断言成为肯定/正向匹配和否定/负向匹配
对于正则表达式的一些整理
我们可以运用以上的符号来判断前瞻后顾,具体怎么用呢,其实就是类似于在代码里面添加if else判断条件
a23.replace(/\w(?=\d)/g,‘x’);
//x2
3
其中 ?=\d 就是去判断是不是数字,只有满足条件的字母才可以替换

三、一些执行方法
相信以前总被正则表达式的执行方法给整晕了。到底有哪些方法,这些方法又有什么用,有何区别。好吧,本来应该很早就知道的东西了,就是因为太懒了,一直没有去整理。

执行正则表达式时,有test和exec方法。

(1)RegExp.prototype.test(str)
这个方法的目的用于测试字符串参数中是否存在匹配正则表达式模式的字符串。
通常,我们用这个方法来做页面上的一些参数校验,通过返回true,不通过则返回为false。

var reg1 = /\w/
reg1.test('a');
// true

var reg1 = /\w/g;
reg1.test('a');
// true
reg1.test('a');
//false
reg1.test('a');
// true
reg1.test('a');
// false

reg1.lastIndex 当前匹配结果的最后一个字符的最后一个字符,匹配并不是从第一个开始的,会记录每一次的过程。比如说这次是从下标为0的地方开的,那么下次的记录则是从2或者是从符合条件的下标开始的。

(2)RegExp.prototype.exec(str)
使用正则表达式对字符串执行搜索,并将全局RegExp对象的属性以反映匹配结果
如果匹配到了返回null,没有返回一个结果数组
index --声明匹配文本的第一个字符的位置

与test相比,他有何不同?
非全局调用下
调用非全局的RegExp对象的exec时,返回数组
第一个元素是与正则表达式相匹配的文本
第二个元素是与RegExpObject的第一个子表达式相匹配的文本
第三个元素是与RegExp对象的第二个子表达式相匹配的文本

var reg3 = /\d(\w)(\w)\d/;
var ts = "1az2bb3cy4dd5ee";
var ret = reg3.exec(ts);
console.log(reg3.lastIndex + '\t'+ret.index + '\t' + ret.toString());
// 0	0	1az2,a,z

这里的lastIndex 对非全局无用,如果要找第一个就用非全局的。

var reg5 = /\d(\w)(\w)\d/g; --改成全局的
var ts = "1az2bb3cy4dd5ee";
var ret5 = reg5.exec(ts);
// 如果想拿到更多的值,那么要加上
console.log(reg5.lastIndex + '\t'+ret5.index + '\t' + ret5.toString());
// 4	0	1az2,a,z

4是怎么来的? 我们按laz2 bb3cy类似这样去分组,lastIndex当前匹配的下一个字符是b,所以输出的是4
index是当前匹配的
laz2是匹配的分组,按z,2进行的分组

四、和正则表达式相关的一些字符串对象方法
(1) String.prototype.search()
–用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串
–返回第一个匹配结果index,差不多返回-1
–不执行全局匹配,忽略标志g,并且总是从字符串的开始进行检索
‘aa’.search(‘1’) // -1
‘aa’.search(’/1/’) // -1

(2)String.prototype.match(reg);
作用:
1.检索字符串,以找到一个或多个与regexp匹配的文本
2.regexp是否具有标志g对结果影响很大

非全局下
只在字符串中执行一次匹配
没有找到返回null,找到了返回一个数组

返回数组的第一个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本
除了常规的数组元素之外,返回的数组还含有2个对象属性
index 声明匹配文本的起始字符在字符串的位置
input 声明对stringObject的引用

全局调用下
如果regexp 具有标志g则进行全局检索,找到字符串中的所有匹配子字符串
–没有找到匹配的子串,则返回null
–如果找到了一个或多个匹配子串,则返回一个数组
数组元素每项都是匹配子串,没有什么input属性

var reg5 = /\d(\w)(\w)\d/g; --改成全局的
var ts = "1az2bb3cy4dd5ee";
var ret5 = ts.match(reg5);
//  ["1az2", "3cy4"]

(3) String.prototype.split(reg)
我们比较常用的场景是把字符串弄成’,'分割成数组
对于比较复杂的字符串,实际可以传入正则表达式,进行分割

'a1b2c3d4e'.split(/\d/g);
//  ["a", "b", "c", "d", "e"]

(4) String.prototype.replace(reg)
–找谁,替换谁
replace有两个入参,第一个可以是字符,也可以是正则表达式
replace(reg, function)
funtion这里是一个回调函数,有四个入参
1.匹配字符串
2.正则表达式分组内容,没有分组则没有该参数
3.匹配项在字符串中的index
4.原字符串
例如:'a1b2c3d4e5’想要把这个字符串中的数字都加1
var str = ‘a1b2c3d4e5’;
str.replace(/\d/g, function(match, index, str){
return parseInt(match) + 1;
})

最后一个环节,我要添加一下,常用的正则表达式,给我自己学习学习。毕竟还是要多多联系嘛。从github上贴来,这篇文章也讲得很不错https://github.com/cdoco/learn-regex-zh star一下,算是小白的启蒙课程了。

正整数: ^\d+$
负整数: ^-\d+$
电话号码: ^+?[\d\s]{3,}$
电话代码: ^+?[\d\s]+(?[\d\s]{10,}$
整数: ^-?\d+$
用户名: ^[\w\d_.]{4,16}$
字母数字字符: ^[a-zA-Z0-9]*$
带空格的字母数字字符: ^[a-zA-Z0-9 ]*$
密码: ^(?=^.{6,}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$
电子邮件: ^([a-zA-Z0-9._%-]aaa@qq.com[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})*$
IPv4 地址: ^((?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))*$
小写字母: ^([a-z])*$
大写字母: ^([A-Z])*$
网址: ^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$
VISA 信用卡号码: ^(4[0-9]{12}(?:[0-9]{3})?)*$
日期 (MM/DD/YYYY): ^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}$
日期 (YYYY/MM/DD): ^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$
万事达信用卡号码: ^(5[1-5][0-9]{14})*$