• 作者:老汪软件技巧
  • 发表时间:2024-09-24 00:03
  • 浏览量:

定义

正则表达式(reg)是前端中非常重要的知识,那么正则表达式到底是什么东西呢?简单来说,正则表达式是用于匹配字符串中字符组合的模式,就是用来做字符串匹配的。比如我们判断字符串中是否包含某个子串,文本替换,判断手机号、邮箱的格式是否合法,判断密码的安全性,这些功能都是用到了正则表达式。许多语言都支持正则表达式,在js中,正则表达式也是对象。

语法

正则表达式的语法:/正则表达式/修饰符(可选),js中定义正则表达式:const 变量名 = /正则表达式/修饰符。斜杠里的是用于检索的正则表达式主体,修饰符是对检索起到补充作用,比如i(ignore)是忽略大小写,g(global)是全局匹配,m是多行匹配。

const reg = /hello/i; //  正则表达式hello忽略大小写

常用方法

正则表达式常用的方法有很多,有些是正则表达式调用的方法,有些是字符串调用的方法,我个人感觉它们长得真的很相似,不过有有些差别,使用的时候需要注意不要搞混了

正则表达式的方法exec():查找符合正则表达式规则的字符

const reg = /hello/i;
const str = 'Hello World';
const res1 = reg.test(str); // true
console.log(res1); 
const res2 = reg.exec(str); // ['Hello', index: 0, input: 'Hello World', groups: undefined]
console.log(res2); 

字符串的方法search():查找字符串中第一个符合规则的字符的索引match():查找字符串中符合规则的字符

const reg = /hello/i;
const str = 'Hello World';
const res3 = str.replace(reg, 'hi'); // 'hi World'
console.log(res3);
const res4 = str.search(reg); // 0
console.log(res4);
const res5 = str.match(reg); // ['Hello']
console.log(res5);

元字符

元字符是一种区别于普通字符的一种特殊字符,具有更好的灵活性和更强的匹配功能。

比如:匹配26个字母,用普通字符要把26个字母全部打出来,但用元字符只需要[a-z]就可以表示

有几种常用的元字符,分别是用来限制边界的边界符,用来限制数量的量词,和字符类。

边界符单词边界

我们想要替换掉某句话中的某个单词,如果使用普通的正则表达式,可能会误匹配到其他包含这个小单词的其他单词,比如想要替换cat,却替换掉了scattered中的cat,单词边界符\b可以解决这种情况。在正则表达式的斜线中间加上一对单词边界符后,匹配的时候就会只筛选与正则表达式完全匹配的单词,其他长单词不会受影响。

const reg = /\bcat\b/g;
const str = 'The cat scattered his food all over the floor.';
console.log(str.replace(reg, 'dog')); // The dog scattered his food all over the floor.

字符串边界

用来限制匹配字符串的开头和结尾。

正则表达式子表达式_正则表达式书写_

const reg1 = /^a/; // 以a开头
console.log(reg1.test('abc')); // true
console.log(reg1.test('bca')); // false
const reg2 = /c$/; // 以c结尾
console.log(reg2.test('abc')); // true
console.log(reg2.test('bca')); // false
const reg3 = /^a$/; //精确匹配,全等
console.log(reg3.test('a')); // true
console.log(reg3.test('aaa')); // false

量词

用来限制匹配字符串的字母数量

        // *:匹配0个或多个字符
        const reg4 = /^a*$/; //以a开头结尾,可以有0个或多个a
        console.log(reg4.test('')); // true
        console.log(reg4.test('a')); // true
        console.log(reg4.test('aaa')); // true
        console.log(reg4.test('aba')); // false
        // +:匹配1个或多个字符
        const reg5 = /^a+$/; //以a开头结尾,必须有1个或多个a
        console.log(reg5.test('')); // false
        console.log(reg5.test('a')); // true
        console.log(reg5.test('aaa')); // true
        console.log(reg5.test('aba')); // false
        // ?:匹配0个或1个字符
        const reg6 = /^a?$/; //以a开头结尾,可以有0个或1个a
        console.log(reg6.test('')); // true
        console.log(reg6.test('a')); // true
        console.log(reg6.test('aa')); // false
        console.log(reg6.test('ab')); // false
        
        // {n}:匹配n个字符
        const reg7 = /^a{2}$/; //以a开头结尾,必须有2个a
        console.log(reg7.test('')); // false
        console.log(reg7.test('a')); // false
        console.log(reg7.test('aa')); // true
        console.log(reg7.test('aba')); // false    
        
        // {n,}:匹配大于等于n个字符
        const reg8 = /^a{2,}$/; //以a开头结尾,必须有大于等于2个a
        console.log(reg8.test('a')); // false
        console.log(reg8.test('aa')); // true
        console.log(reg8.test('aba')); // false
        console.log(reg8.test('aaa')); // true
        // {n,m}:匹配n到m个字符
        const reg9 = /^a{2,3}$/; //以a开头结尾,必须有2到3个a
        console.log(reg9.test('a')); // false
        console.log(reg9.test('aa')); // true
        console.log(reg9.test('aaa')); // true
        console.log(reg9.test('aaaa')); // false

字符类

上面的例子中的[a-z]表示匹配小写字母a到z中的任意一个,[]和-就是字符类元字符

        // 匹配字符集合[]:匹配括号范围内的字符
        const reg10 = /[abc]/; // 匹配a、b、c中的任意一个字符
        console.log(reg10.test('apple')); // true
        console.log(reg10.test('banana')); // true
        console.log(reg10.test('cindy')); // true
        console.log(reg10.test('dirty')); // false
        // 连字符-:匹配范围缩写
        const reg11 = /[a-z]/; // 匹配a到z中的任意一个字符
        const reg12 = /[0-9]/; // 匹配0到9中的任意一个数字
        const reg13 = /[a-zA-Z]/; // 匹配a到z和A到Z中的任意一个字符
        const reg14 = /[a-zA-Z0-9_]/; // 匹配a到z、A到Z、0到9和下划线中的任意一个字符
        // 取反^:匹配不在括号内的字符,注意要写在集合里
        const reg15 = /[^0-9]/; // 匹配除了数字的任意字符
        console.log(reg15.test('aaa')); // true
        console.log(reg15.test('111')); // false
        console.log(reg15.test('a1')); // true
        // .:匹配除换行符外的任意字符
        const reg16 = /./; // 匹配除换行符外的任意字符        
        console.log(reg16.test('')); // false
        console.log(reg16.test('a')); // true
        console.log(reg16.test(' ')); // true
        console.log(reg16.test('\n')); // false
        const reg17 = /hello.world/; // 匹配hello后面跟着任意字符,再跟着world
        console.log(reg17.test('helloworld')); // false
        console.log(reg17.test('hello world')); // true
        console.log(reg17.test('hello')); // false
        // 预定义字符类:\d:匹配数字 \D:匹配非数字 \w:匹配字母数字下划线 \W:匹配非字母数字下划线 \s:匹配空白字符(换行空格制表符) \S:匹配非空白字符
        const reg18 = /\d/; // 匹配数字,等价于[0-9]
        const reg19 = /\D/; // 匹配非数字,等价于[^0-9]
        const reg20 = /\w/; // 匹配字母数字下划线,等价于[a-zA-Z0-9_]
        const reg21 = /\W/; // 匹配非字母数字下划线,等价于[^a-zA-Z0-9_]
        const reg22 = /\s/; // 匹配空白字符,等价于[\f\n\r\t\v]
        const reg23 = /\S/; // 匹配非空白字符,等价于[^\f\n\r\t\v]

分组和分支结构

在进行字符串匹配时,如果我们想匹配多个连续的ab,应该怎么办呢?/ab+/?哒咩哟,这样只能匹配abbbbb,这时候我们就需要给ab加上个括号,也就是/(ab)+/,这样就可以把ab看成一个整体了,量词+也就会作用于ab这个整体。

        //分组:把需要看成整体的部分用括号括起来
        const reg = /(ab)+/; // 匹配连续出现的 ab
        console.log(reg.test('ab')); // true
        console.log(reg.test('abab')); // true
        console.log(reg.test('aabbb')); // true

分组捕获

上面我们知道了括号就是一种分组,下面有一道新问题:如果要把年-月-日改成月/日/年应该如何操作呢?这就不得不提到分组捕获。

普通的匹配模式是/^\d{4}-\d{2}-\d{2}$/,这样是把日期作为一个组(group)来匹配,我们把这样的叫Group0。但是如果我们在年月日的外面都加上括号/^(\d{4})-(\d{2})-(\d{2})$/,就相当于把日期分成了三个组:YYYY-MM-DD是Group0,YYYY是Group1,MM是Group2,DD是Group3。使用$符号来获取每个组的内容,比如$1代表YYYY。最后用replace方法修改字符串的内容。完整代码如下:

        // 分组捕获:把匹配到的内容保存起来,可以用 $1、$2、$3... 来引用
        const reg1 = /^\d{4}-\d{2}-\d{2}$/; // 不分组匹配日期格式
        const reg2 = /^(\d{4})-(\d{2})-(\d{2})$/; // 分组匹配日期格式,并捕获年、月、日
        const date = '2021-08-12';
        console.log(reg1.test(date)); // true
        console.log(reg2.exec(date)); // ["2021-08-12", "2021", "08", "12", index: 0, input: "2021-08-12"]
        console.log(date.replace(reg2, '$2/$3/$1')) // "08/12/2021"

分支结构

其实就是或操作符|,表示匹配规则1或规则2

        // 分支结构
        const str1 = '学水利找河海';
        const str2 = '学电气找河海';
        const str3 = '学计算机找b站';
        const reg3 = /水利|电气/; // 匹配 "水利" 或 "电气"
        console.log(reg3.test(str1)); // true
        console.log(reg3.test(str2)); // true
        console.log(reg3.test(str3)); // false

实例

下面举几个例子来实践一下正则表达式的知识

        // 密码匹配(6-16位字母、数字或下划线)
        const reg1 = /^\w{6,16}$/;
        console.log(reg1.test('123456_')); // true
        // 匹配16进制颜色值
        const reg2 = /^#([0-9a-fA-F]{6}|([0-9a-fA-F]{3})$)/;
        console.log(reg2.test('#FF0000')); // true
        // 匹配24h小时制的时间
        const reg3 = /^([01][0-9])|(2[0-3]):[0-5][0-9]$/;
        console.log(reg3.test('12:30')); // true
        // 手机号码脱敏
        const reg4 = /^(1[3-9]\d)\d{4}(\d{4})$/;
        const mobile = '13812345678';
        console.log(reg.test(mobile)); // true
        console.log(mobile.replace(reg4, '$1****$2')); // 138****5678