【JavaScript】正则表达式详解

💻【JavaScript】正则表达式🏠专栏:JavaScript
👀个人主页:繁星学编程🍁
🧑个人简介:一个不断提高自我的平凡人🚀
🔊分享方向:目前主攻前端,其他知识也会阶段性分享🍀
👊格言:☀️没有走不通的路,只有不敢走的人!☀️
👉让我们一起进步,一起成为更好的自己!!!🎁

【JavaScript】正则表达式

正则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)使用单个字符串来描述、匹配一系列符合某个句法规则的字符串搜索模式。

一. 什么是正则表达式?

正则表达式是由一个字符序列形成的搜索模式。
当你在文本中搜索数据时,你可以用搜索模式来描述你要查询的内容。
正则表达式可以是一个简单的字符,或一个更复杂的模式。
正则表达式可用于所有文本搜索和文本替换的操作。

二. 创建正则表达式

(1) 内置构造函数方式创建

语法:

let 变量 = new RegExp("正则表达式","修饰符");

参数:

  • 正则表达式:可以是字符串或者变量
  • 修饰符:可以是全局匹配(g)、忽略大小写(i)、多行匹配(m)
// eg: 判断字符串(abCDcs)中是否有(abcd),并且全局匹配(g)、忽略大小写(i)
let reg = new RegExp('abcd', 'ig');
console.log(reg.test('abCDcs')); // true

(2) 字面量方式创建

语法:

let 变量 = /正则表达式/修饰符

:使用字面量创建的正则表达式只能是字符串

// eg:
let reg = /abcd/ig;
console.log(reg.test('abCDcs')); // true

三. 正则表达式修饰符

修饰符 可以在全局搜索中不区分大小写:

i(ignore case):忽略大小写
g(global):执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)
m(multiple lines):执行多行匹配

设置匹配模式时,可以都不设置,也可以设置1个,也可以全设置,设置时没有顺序要求。

四. 正则表达式的方法

(一) 正则对象的方法

(1) test()

概念:用于检测一个字符串是否匹配某个模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false。
语法:正则表达式.test(字符串)
返回值:返回一个布尔值,如果字符串中含有匹配的文本,则返回 true,否则返回 false。

let a = new RegExp("e");// 检查下列句子中是否含有e
document.write(a.test("There is a good thing"));
<!-- 结果:true -->
(2) exec()

概念:在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。
语法:正则表达式.exec(字符串)
返回值:把字符串中符合正则要求的第一项以及一些其他信息,以数组的形式返回

:该方法是将字符串中满足正则表达式的部分提取出来

let reg = /\d[a-z]/;
let str = "ab56efg";
let res = reg.exec(str);
console.log(res);
// ['6e', index: 3, input: 'ab56efg', groups: undefined]
/*
	返回值中的第一项:匹配的值('6e')
	第二项:匹配的索引,只找第一个(index: 3)
	第三项:匹配的字符串(input: 'ab56efg')
	第四项:分组(这里没有所以,groups: undefined)(可以忽略)
*/
//遇到满足条件的就返回,所以只返回5

(二) 字符串支持的正则方法

(1) split()

概念:将一个字符串拆分为一个数组
语法:字符串.split(正则表达式/字符串)
返回值:返回被拆分后的数组

let str = "1j1j1k2d7o";
console.log(str.split("k")); // ['1j1j1', '2d7o']
let result = str.split(/[A-z]/);
console.log(result); // ['1', '1', '1', '2', '7', '']
(2) replace()

概念:用于在字符串中用一些字符串替换另一些字符串,或替换一个与正则表达式匹配的子串。
语法:字符串.replace(换下字符串,换上字符串)

:第二参数可以是字符串也可以是回调函数

// eg: 使用正则表达式且不区分大小写将字符串中的 Cat 替换为 Root
var str = "Visit Cat !";
var txt = str.replace(/cat/i,"Root");

结果输出为:Visit Root !

// eg: 批量替换敏感词
var arr = ['HH', 'MM', 'NN']
var str = 'aHHdfasMMdfaNNdsfaNNsNNdffas'
var reg = new RegExp(arr.join("|"), "g")
console.log(str.replace(reg, '**')); // a**dfas**dfa**dsfa**s**dffas
(3) match()

概念:检索返回一个字符串匹配正则表达式的结果。
语法:字符串.match(正则表达式)
返回值:以数组的格式返回满足条件的第一项

var reg=/[a-z]/g;
var str="ab56efg";
var res=str.match(reg); //字符串中满足表达式的部分提取出来
console.log(res);//结果:['a', 'b', 'e', 'f', 'g']

match() 和exec()的同异点

区别

  • exec()方法是:正则表达式提供的方法
  • match()方法是:字符串的方法

相同: 都返回一个数组,只要匹配到符合规则的数据就返回

(4) search()

search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并$\color{red} {返回子串的起始位置} $。
语法:字符串.search(正则表达式)
返回值:找到目标值返回对应的索引,没找到返回-1.

// eg:使用正则表达式搜索 "Root" 字符串,且不区分大小写
var str = "Visit Root!"; 
var n = str.search(/Root/i); 
console.log(n); // 6

五. 正则表达式模式

(1) 方括号

方括号用于查找某个范围内的字符:

表达式描述
[abc]查找方括号之间的任何字符。
[0-9]查找任何从 0 至 9 的数字。
(x|y)查找任何以 | 分隔的选项。
// eg: 匹配数字字母中的任意一个字符
[a-zA-Z0-9]

(2) 元字符

元字符(Metacharacter)是拥有特殊含义的字符:

元字符描述
.(小数点)默认匹配除换行符之外的任何单个字符。
\w匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_]
\W匹配一个非单字字符。等价于 [^A-Za-z0-9_]
\d查找数字(至少含有一个数字(0~9))
\D查找非数字字符(至少含有一个非数字)
\s查找空白字符(至少含有一个空白字符(空格、缩进、\b…))
\S查找非空白字符(至少含有一个不是空白字符)
\b匹配单词边界
\B匹配非单词边界
\0查找NUL字符
\n查找换行符
\f查找换页符
\r查找回车符
\t查找制表符
\v查找垂直制表符
\xxx查找以八进制 xxx 规定的字符
\xdd查找以十六进制 dd 规定的字符
\uxxxx查找以十六进制 xxxx 规定的 Unicode 字符

实例

var reg = /\W/  //true
console.log(reg.test("!@#!"))
var reg = /\D/  //false
console.log(reg.test("123"))
var reg = /\bchild\b/  //false
console.log(reg.test("hello children"))

(3) 量词

量词描述
?出现0次或一次
+出现一次或多次
*出现0次或多次
{n}出现n次
{n,m}出现n到m次
{n,}至少出现n次

实例

var reg = /a{3}/;//判断a是否连续出现3次
console.log(reg.test("aaabc"));//true
console.log(reg.test("abc"));//false
var reg = /(ab){3}/;//判断ab是否连续出现3次
console.log(reg.test("abababc"));//true
console.log(reg.test("abc"));//false
var reg = /ab{1,3}c/;//判断b是否连续出现1-3次
console.log(reg.test("abbbc"));//true
console.log(reg.test("abbbbbc"));//false
console.log(reg.test("bac"));//false

(4) 正则语法

正则描述
|
[ ]
[^ ]除了
[a-z]小写字母
[A-Z]大写字母
[A-z]任意字母
^开头
$结尾

实例:

//检查字符串中是否含有a或b
var reg = /a|b/
console.log(reg.test("bcd"))//结果:true
//检查字符串中是否含有字母
var reg = /[a-z]/
console.log(reg.test("bcdfsji"))//结果:true
//检查字符串中是否含有abd或abc或abf
var reg = /ab[cdf]/
console.log(reg.test("bcabcji"))//结果:true
//检查一个字符串是否以a结尾
var reg = /a$/
console.log(reg.test("bcabcjia"))//结果:true
//如果在正则表达式中同时使用^ $则要求必须完全符合正则表达式
var reg = /^a$/
console.log(reg.test("as"))//结果:false

(5) 重复元字符

符号: \数字

作用: 表示重复第n个小括号的内容,要求和第n个小括号的内容一模一样

// 表示这个()里面的整体内容出现2次就可以。不要求一模一样
// var reg1 = /^(abc|def){2}$/

// 表示 \1 位置 需要出现一个 和 第一个 小括号 一模一样的内容
var reg1 = /^(abc|def)\1$/
console.log(reg.test('abcabc')); // true
console.log(reg.test('defdef')); // true
console.log(reg.test('abcdef')); // false

var reg2 = /^(abc|def)(哈哈|嘻嘻)\2$/
console.log(reg.test('abc哈哈哈哈')); // true
console.log(reg.test('abc哈哈嘻嘻')); // false
console.log(reg.test('abc嘻嘻嘻嘻')); // true

(6) 正则的捕获方式

语法:正则表达式.exec(字符串)
作用:始字符串中捕获到符合正则规则的字符串片段

返回值

  1. 当原始字符串没有符合规则的时候,返回null

  2. 当原始字符串由符合规则的片段的时候:

    返回值必然是一个数组,数组的[0] 是捕获出来的字符串片段

    • 没有(), 没有g

      不管写多少次,只能捕获第一组匹配规则的字符串片段

      var reg = /\d{3}/
      var str = 'adfa123sals456hdfl789kasakhdf012'
      var res = reg.exec(str)
      console.log(res); // ['123', index: 4, input: 'adfa123sals456hdfl789kasakhdf012', groups: undefined]
      console.log(reg.exec(str)); // ['123', index: 4, input: 'adfa123sals456hdfl789kasakhdf012', groups: undefined]
      console.log(reg.exec(str)); // ['123', index: 4, input: 'adfa123sals456hdfl789kasakhdf012', groups: undefined]
      
    • 有()

      会在返回值数组的[1]开始,依次是每一个()中单独的内容

      var reg = /(\d{2})(\d{2})(\d{2})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(\d|x)/
      var str = '22230120050101123x'
      console.log(reg.exec(str));
      // ['22230120050101123x', '22', '23', '01', '2005', '01', '01', '12', '3', 'x', index: 0, input: '22230120050101123x', groups: undefined]
      
    • 有g

      g 叫做全局标识符

      第二次捕获开始会从第一次捕获的结束为止开始检索

      直到找不到内容,返回null

      var reg = /\d{3}/g 
      var str = 'adfa123sals456hdfl789kasakhdf012'
      console.log(reg.exec(str)); // ['123', index: 4, input: 'adfa123sals456hdfl789kasakhdf012', groups: undefined]
      console.log(reg.exec(str)); // ['456', index: 11, input: 'adfa123sals456hdfl789kasakhdf012', groups: undefined]
      console.log(reg.exec(str)); // ['789', index: 18, input: 'adfa123sals456hdfl789kasakhdf012', groups: undefined]
      

匹配但是不捕获

当我们需要使用()这个整体作用,但是不需要把()里面的内容单独捕获的时候:可以书写( ?: )

六. 正则的两大特性

  1. 懒惰

    每次捕获的时候都会从字符串[0]开始检索
    解决:给正则添加标识符g,(查找所有匹配而非在找到第一个匹配后停止)

  2. 贪婪

    每次在捕获内容的时候,尽可能多的去捕获内容
    解决:使用非贪婪限定符(在原来的限定符后面加一个?)

// 贪婪捕获
let str = '1234567abcd'
let reg = /\d*/
console.log(reg.exec(str)); // ['1234567', index: 0, input: '1234567abcd', groups: undefined]

贪婪限定符:(*、+、?、{n,}、{n,m})

// 贪婪限定符
let reg = /<div.*>/
console.log(reg.exec(str)); // '<div class="box" id="box"><span></span></div>'

非贪婪限定符:(*?、+?、??、{n,}?、{n,m}?)

// 非贪婪限定符
let reg = /<div.*?>/
console.log(reg.exec(str)); // '<div class="box" id="box">'

七. ES9新特性(正则扩展)

(1) 命名捕获分组

捕获:对正则匹配的数据进行(.*)单独提取。

// 声明一个字符串 
let str = '<a href="http://www.baidu.com">你好</a>'; 
// 需求:提取url和标签内文本 
// 之前的写法 
const reg = /<a href="(.*)">(.*)<\/a>/; 
const result = reg.exec(str); 
console.log(result); 
// 结果是一个数组,第一个元素是所匹配的所有字符串 
// 第二个元素是第一个(.*)匹配到的字符串 
// 第三个元素是第二个(.*)匹配到的字符串 
// 我们将此称之为捕获 
console.log(result[1]); // http://www.baidu.com
console.log(result[2]); // 你好

// 使用命名捕获分组的写法:
const reg1 = /<a href="(?<url>.*)">(?<text>.*)<\/a>/; 
const result1 = reg1.exec(str); 
console.log(result1); 
// 这里的结果多了一个groups 
// groups: 
// text:"你好" 
// url:"http://www.baidu.com" 
console.log(result1.groups.url); // http://www.baidu.com
console.log(result1.groups.text); // 你好

结果:
请添加图片描述

(2) 反向断言

断言:判断这次的匹配结果是否正确

正向断言/反向断言 做一个唯一性的识别
正向断言(目标的后面)

let str = "JS314你知道么5呀"; 
// 需求:我们只想匹配到5 
// 正向断言 
const reg = /\d+(?=呀)/;  
const result = reg.exec(str); // ['5', index: 9, input: 'JS314你知道么5呀', groups: undefined]

结果:
请添加图片描述
反向断言(目标的前面)

let str = "JS314你知道么5呀";
// 反向断言 
const reg1 = /(?<=么)\d+/;
const result1 = reg1.exec(str);
console.log(result1); // ['5', index: 9, input: 'JS314你知道么5呀', groups: undefined]

结果:
请添加图片描述

(3) dotAll 模式

dot就是. 元字符,表示除换行符之外的任意单个字符

之前的写法:

let str = `
<ul>
    <li>
        <a href="#">a</a>
        <p>b</p>
    </li>
    <li>
        <a href="#">c</a>
        <p>d</p>
    </li>
</ul>
`;
const reg = /<li>\s+<a href="#">(.*?)<\/a>\s+<p>(.*?)<\/p>/;
console.log(reg.exec(str));

结果:
请添加图片描述

使用dotAll后:

let str = `
<ul>
    <li>
        <a href="#">a</a>
        <p>b</p>
    </li>
    <li>
        <a href="#">c</a>
        <p>d</p>
    </li>
</ul>
`;
// const reg = /<li>\s+<a href="#">(.*?)<\/a>\s+<p>(.*?)<\/p>/g;
const reg = /<li>.*?<a href="#">(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
// console.log(reg.exec(str));
let result;
while ((result = reg.exec(str))) console.log(result);

g为全局匹配 匹配不到是返回null,结束循环

结果:
请添加图片描述

八. 案例

案例一:书写正则验证用户名

规则

  • 6 ~ 12 位
  • 只能包含数字字母下划线 \w
  • 不能以 下划线开头
var reg = /^[0-9a-zA-Z]\w{5,11}$/

案例二:书写正则验证邮箱

规则

  • @ 前面, 和用户名规则一致
  • 邮箱类型只接受 163 qq sina
  • 后缀只接受 com cn
var reg = /^[0-9a-zA-Z]\w{5,11}@(163|qq|sina)\.(com|cn)$/

案例三:书写正则验证手机号

规则

  • 前面有可能带有 +86 有可能没有 ? {0,1}
  • +86 和 电话号之间有可能有空格有可能没有
  • 号段只接受 133 135 188
var reg = /^(\+86 ?)?(133|135|188)\d{8}$/

案例四:书写正则验证 0 ~ 255 的数字

var reg = /^(\d{1,2}|1\d{2}|2[0-4]\d|25[0-5])$/
<!-- 验证:0 ~ 666 -->
var reg = /^(\d{1,2}|[1-5]\d{2}|6[0-5]\d|66[0-6])$/

案例五:连字符和驼峰之间的转换

// 连字符转驼峰
let str = 'get-element-by-id';
let res = str.replace(/-[a-z]/g, function (result) {
    return result.slice(1).toUpperCase();
})
console.log(res); // getElementById
// 驼峰转连字符
let str = 'getElementById'
let res = str.replace(/[A-Z]/g, function (result) {
    return '-' + result.slice(0).toLowerCase();
})
console.log(res); // get-element-by-id

案例六:封装函数实现字符串首尾空格

function reTrim(str) {
    // 首先判断是不是一个字符串
    if (!typeof str === 'string') return;
    return str.replace(/^\s+|\s+$/g, '');
}
console.log(reTrim(str));

案例七:敏感词替换

// eg: 批量替换敏感词
var arr = ['HH', 'MM', 'NN']
var str = 'aHHdfasMMdfaNNdsfaNNsNNdffas'
var reg = new RegExp(arr.join("|"), "g")
console.log(str.replace(reg, '**')); // a**dfas**dfa**dsfa**s**dffas

结束语

希望对您有一点点帮助,如有错误欢迎小伙伴指正。
👍点赞:您的赞赏是我前进的动力!
⭐收藏:您的支持我是创作的源泉!
✍评论:您的建议是我改进的良药!
一起加油!!!💪💪💪

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星学编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值