深入理解 JavaScript 之 正则表达式

本文深入介绍了正则表达式的概念、用途、工具及核心元素,包括普通字符、元字符、预定义字符集、量词、边界匹配等。详细阐述了如何使用正则表达式进行字符串验证、查找、替换和提取操作,并对比了不同方法的适用场景。同时,探讨了贪婪与非贪婪模式,并列举了多种正则表达式在JavaScript中的应用方法,如indexOf、includes、search、match、test和exec。最后,总结了正则表达式的验证、切割、提取和替换方法及其应用场景。

在我们写页面时,往往需要对表单的数据比如账号、身份证号等进行验证,而最有效的、用的最多的便是使用正则表达式来验证。那什么是正则表达式呢?

1、简介

正则表达式(Regular Expression)是用于描述一组字符串特征的模式,用来匹配特定的字符串。

1.1 用途

它的应用非常广泛,特别是在字符串处理方面,通过这个规则来匹配、查找、替换或切割那些符合指定规则的文本。其常见的应用如下

  • 验证字符串,即验证给定的字符串或子字符串是否符合指定的特征,例如,验证是否是合法的邮件地址、验证是否是合法的HTTP地址等等。

  • 查找字符串,从给定的文本当中查找符合指定特征的字符串,这样比查找固定字符串更加灵活。

  • 替换字符串,即查找到符合某特征的字符串之后将之替换。

  • 提取字符串,即从给定的字符串中提取符合指定特征的子字符串

2、 工具

正所谓工欲善其事必先利其器! 所以我们需要知道下面几个主要的工具:

3、正则表达式中的字符

正则表达式中的字符分为 普通字符元字符,而正则表达式就是这些普通字符和特殊元字符组合成的表示一个特定匹配规则的表达式。

3.1 普通字符

大多数字符都将简单地匹配它们的自身值,它们被称为普通字符。如数字(0-9),字母(a-z, A-Z)等

提示: 其实我们并不需要去记忆哪些字符是普通字符,我们只需要知道哪些字符是特殊元字符就可以了,除了特殊元字符之外的所有字符都是普通字符。

3.2 元字符

正则表达式除了进行字符自身之的匹配外,还可以 基于指定的规则进行模糊匹配。这就意味着它 需要一些特殊字符来表示这些模糊的匹配规则,因此 这些特殊字符默认情况下并不能匹配到它们自身的字面值,而是表示某些特殊的功能

这些特殊元字符包括:., [, ], (, ), *, +, ?, ^, $, , |

提示: 那么如果想匹配这些特殊元字符本身的字面值怎么办呢?我们可以通过其中一个特殊字符对其它特殊字符进行转义,从而达到可以匹配这些特殊字符自身字面值的目的。

4、 元字符详解

4.1 单个字符匹配

在这里插入图片描述

说明:

所有的特殊字符在 [ ] 内都将失去其原有的特殊含义:

  • 有些特殊字符在 [ ] 中被赋予新的特殊含义,如 '^'出现在 [ ] 中的开始位置表示取反,它出现在 [ ] 中的其他位置表示其本身(变成了一个普通字符);

  • 有些特殊字符则变为普通字符,如 '.', '*', '+', '?', '$'

  • 有的普通字符变为特殊字符,如 '-'[ ] 中的位置不是第一个字符则表示一个数字或字母区间,如果在 [ ] 中的位置是第一个字符则表示其本身(一个普通字符)

  • [ ] 中,如果要使用'-', '^' 或']'可在在它们前面加上反斜杠,或把'-', ']'放在第一个字符的 位置,把'^'放在非第一个字符的位置。

4.2 预定义字符集

我们可以在反斜杠后面跟上一个指定的字母来表示预定义的字符集合

在这里插入图片描述

4.3 字符次数匹配–量词

在正则表达式中,我们还可以指定匹配某个字符出现次数

在这里插入图片描述

说明:
{m,n}中的 m 和 n 可以省略其中一个,{,n}相当于{0,n}{m,}相当于{m,整数最大值}

我们可以得出以下结论:

  • {0,1}{,1} 等价于 ?
  • {1,} 等价于 +
  • {0,} 等价于 *

我们优先选择使用 ?, + 和 *,因为他们书写简单,也可以使整个正则表达式变得简洁。

说明: ? 这个字符在正则表达中与 ?, +, *, {m,n}连用时还有一个额外的功能,就是将匹配模式由贪婪模式(尽可能的增加匹配次数) 变成 非贪婪模式(尽可能减少匹配次数)
这个会在下面的内容中进行详细说明。

4.4 边界匹配

正则表达式中还可以对边界位置进行匹配,如一个字符串的开头或结尾,一个单词的开头或结尾。
在这里插入图片描述

4.5 逻辑与分组

在这里插入图片描述

4.6 特殊构造

在这里插入图片描述

说明:
上面所说的“不消耗字符串内容”是指只是进行匹配,但是不移动原始字符串的匹配位置,这样就可以完成多次匹配。下面有个匹配密码的正则表达式实例,就是用这个特性巧妙完成的。

一张经典的总结图(收藏了很久,忘记了出处,如果哪位知道请告知,这里会附上链接地址,谢谢。)
在这里插入图片描述

5、正则表达式 - 修饰符(标记)

在这里插入图片描述

6、 贪婪模式与非贪婪模式

6.1 贪婪模式(默认)

在贪婪(默认)模式下,正则引擎尽可能多的重复匹配字符。

示例:

var str = 'a "witch" and her "broom" is one';
str.match( /".*"/g); // ['"witch" and her "broom"']

6.2 非贪婪模式

在非贪婪模式下,正则引擎尽可能少的重复匹配字符。

非贪婪模式和贪婪模式相反,可通过在代表数量的标识符后放置?来开启非贪婪模式,如?、+?甚至是??

示例:

var str = 'a "witch" and her "broom" is one';
str.match(/".*?"/g )     // ['"witch"', '"broom"']

7、正则表达式方法

7.1 验证

方法一: indexOf()

let str = "hello world!";
console.log(str.indexOf("hello") != -1); // true
// 不是正则, 但却是解决当前题的一种方案,
// indexOf()方法返回调用String对象中第一次出现的指定值的索引, 如果未找到该值, 则返回-1

方法二: includes()

let str = "hello world!";
console.log(str.includes("hello")); // true
// includes() 方法用于判断一个字符串是否包含在另一个字符串中, 根据情况返回true或false

方法三: search()

let str = "hello world!";
console.log(str.search(/hello/) != -1);
// 只有一个参数, 并且是一个正则表达式对象, 如果传入一个非正则表达式对象,
// 则会使用 new RegExp(obj)隐式地将其转换为正则表达式对象
// 如果匹配成功, 则返回正则表达式在字符串中首次匹配项的索引, 否则, 返回-1

方法四: match()

let str = "hello world!";
console.log(!!str.match(/hello/g));
// 如果传入一个非正则表达式对象, 则会隐式地使用new RegExp(obj)将其转换为一个RegExp
// 返回值(数组), 如果匹配到数组第一项是匹配的完整字符串, 之后项是用圆括号捕获的结果, 如果没有匹配到, 返回null
// 如果正则表达式包含g标志, 则该方法返回一个Array, 它包含所有匹配的子字符串而不是匹配对象

方法五: test()

let str = "hello world!";
console.log(/hello/.test(str));
// 用来查看正则表达式与指定的字符串是否匹配, 返回true或false
// 想要知道一个模式是否存在于一个字符串中, 可以使用test()或者search

方法六: exec()

let str = "hello world!";
console.log(!!/hello/.exec(str));
// exec() 方法在一个指定字符串中执行一个搜索匹配, 返回一个结果数组或null,
// 如果只是为了判断是否匹配(true或false), 可以使用RegExp.test()方法, 或者String.search()方法

验证总结:

  • 一个确认的( 精准匹配 )字符查找是否被包含, 使用 String.indexOf()String.includes()
  • 一个有规则的( 模糊匹配 )字符查找是否被包含, 使用 RegExp.test()String.search()
  • 查找不推荐, 使用 String.match()RegExp.exec()

7.2 切割

split()

split() 方法使用指定的分隔符字符串将一个String对象分割成字符串数组, 以将字符串分隔为子字符串, 以确认每个拆分的位置

let regex = /,/;
let str = "html,css,javascript";
let str2 = "2018/10/18";
console.log(str.split(regex));
console.log(str2.split(/\//));

7.3 提取

提取:很多时候需要提取部分匹配的数据, 通常需要使用分组引用( 分组捕获 )

方法一: match()

let str = "2018-10-18";
let regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
console.log(str.match(regex));

方法二: exec()

let str = "2018-10-18";
let regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
console.log(regex.exec(str));

方法三: test()

let str = "2018-10-18";
let regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
regex.test(str);
console.log(RegExp.$1, RegExp.$2, RegExp.$3);

方法四: search()

let str = "2018-10-18";
let regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
str.search(regex);
console.log(RegExp.$1, RegExp.$2, RegExp.$3);

方法五: replace()

let str = "2018-10-18";
let regex = /^(\d{4})\D(\d{2})\D(\d{2})$/;
let date = [];
str.replace(regex, function(match, year, month, day) {
  date.push(year, month, day);
});
console.log(date);

提取总结:

  • 本质上是捕获分组 推荐使用matchexec 其中, 最常用的是match

String.match()RegExp.exec() 的主要区别

  • 所属类不同

  • 跟 g 有关

    • match()如果正则表达式包含 g 标志, 则该方法返回一个Array, 它包含所有匹配的子字符串而不是匹 配对象, 捕获组不会被返回( 即不返回 index 属性和 input 属性 )。如果没有匹配到, 则返回null。
    • exec() 方法在一个指定字符串中执行一个搜索匹配, 返回一个结果数组或 null
    • 不包含 g 标志, 则 str.match() 会返回和 RegExp.exec() 相同的结果
  • exec 只会匹配第一个符合的字符串( 意味着 g 对其不起作用 )和所有分组的反向引用, 虽然 g 对其不生效,但其使用 lastIndex 和 while 循环, 可以达到 g 的目的, 这点比 match 强大

  • match 返回的数组内容, 跟正则表达式中是否带 g 有关系( 如果带 g, 包含的是所有匹配的子字符串 ) 如果不带 g == 默认的 exec

7.4 替换

replace()

let str = "2018-10-18";
let regex = /-/g;
console.log(str.replace(regex, "/"));

8、总结

  • 验证一个字符串( 精准匹配 )是否被包含, 使用 String.indexOf() 、 String.includes()

  • 验证一个字符串( 模糊匹配 )是否被包含, 使用 String.search()、RegExp.test()

  • 切分一段字符串( 无论确认字符和规则字符 ), 使用 String.split(字符串/正则)

  • 提取分组捕获信息, 使用 String.match()、RegExp.exec() 注意区分它们之间的区别 -> g

  • 替换, 使用 String.replace(String/RegExp, string/function) 注意第二个参数的的规则信息

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值