Skip to content

正则表达式

正则表达式(英语:Regular Expression,常简写为regexregexp或RE),又称正则表示式、正则表示法、规则表达式、常 规表示法,是计算机科学的一个概念;

  • 正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
  • 许多程序设计语言都支持利用正则表达式进行字符串操作。
  • 简单概况:正则表达式是一种字符串匹配利器,可以帮助我们搜索、获取、替代字符串;

1、JavaScript中创建正则表达式的方式

Section titled “1、JavaScript中创建正则表达式的方式”
  1. 构造器的方式

    //注意: 补充一下 “\” 才是转义符 “/” 不是
    const regexp = new RegExp("规则", "修饰符")
    new RegExp('ab+c', 'i'); // 首个参数为字符串模式的构造函数
    new RegExp(/ab+c/, 'i'); // 首个参数为常规字面量的构造函数
  2. 字面量的方式

    const regexp = /"规则"/"修饰符"
flag含义
g全部的,不使用g修饰符的话只会匹配第一次出现的
i忽略大小写
mmultiple 多行匹配,当存在 /n 换行符的时候。添加限制 例:this an/n on regexp = /an$/. 如果不使用 m 修饰符的话,就会认为 是以 an 结尾的。

字符类(Character classes) 是一个特殊的符号,匹配特定集中的任何符号。

Section titled “字符类(Character classes) 是一个特殊的符号,匹配特定集中的任何符号。”
字符含义
\d(“d” 来自 “digit”)数字:从 0 到 9 的字符。
\s(“s” 来自 “space”)空格符号:包括空格,制表符 \t,换行符 \n 和其他少数稀有字符,例如 \v,\f 和 \r。
\w(“w” 来自 “word”)“单词”字符:拉丁字母数字下划线 _
.(点)指**\n 除外的所有字符**
字符(大写)含义(小写)
\D 非数字除 \d 以外的任何字符,例如字母。
\S 非空格符号除 \s 以外的任何字符,例如字母。
\W 非单字字符除 \w 以外的任何字符,例如非拉丁字母或空格。
  1. ^: 符号 ^ 匹配文本开头
  2. $: 符号 $ 匹配文本末尾;
  • 注意:两边同时都加了锚点的话就代表匹配的字符串 开头结尾中间都要相等

  • 结合使用规则:必须要是 ‘开头’, ‘结尾’, ‘中间’都要是 WYN的字符,

    //例 匹配的字符串必须是 “wyn”
    if(/^wyn$/ig.test("wyn")) {
    console.log("ok")
    } else {
    console.log("fail")
    }
    //规则:必须要是 ‘开头’, ‘结尾’, ‘中间’都要是 WYN的字符,
  • 词边界 \b 位置的一边不能包含 \w 【数字字母下划线】

    就是使用词边界的一侧不能出现 数字,字母,下划线,但可以是空格 ! 不符合 \w

  • 注意:\w 是单词字母,数字,和下划线,不包括字符

如果要把特殊字符作为常规字符来使用,需要对其进行转义:

  • 只需要在它前面加个反斜杠;

[ ] \ ^ $ . | ? * + ( )

  • 注意: 斜杠符号 ‘/’ 并不是一个特殊符号,但是在字面量正则表达式中也需要转义
  • 使用 \ 转义

可以设置一个范围,匹配的字符只需要该范围内其中一个就可以

方括号 […] 中的几个字符或者字符类意味着“搜索给定的字符中的任意一个”;

//效果都是一样的
/[12345]/ig ,/[1,2,3,4,5]/ig, /[1|2|3|4|5]/ig

在集合[ ] 方括号中使用 “-” 可以表示一个范围

  • 例:[a-z] 会匹配从 a 到 z 范围内的字母,[0-5] 表示从 0 到 5 的数字;

  • 表示多个范围:[0-9A-F] 表示两个范围:它搜索一个字符,满足数字 0 到 9 或字母 A 到 F;

    const num = 123;
    console.log(/[110-130]/ig.test(num));

除了普通的范围匹配,还有类似 [^…] 的“排除”范围匹配;

  • 在范围的前面添加 ‘^’ 表示排除当前范围
\d -> [0-9]
\D -> [^0-9]

用来表示当前 regexp 要作用在几个字符的上面

  • 确切的位数:{5}

    表示会有5个a,来满足当前正则

    const regexp = /a{3,5}/igm // 表示3 ~ 5 之间
  • 某个范围的位数:{3,5}

    • 注意:这里的 ,两边不允许添加空格
  • {1, } 表示的是 1 个或者多个 和 + 号的作用表示相同的作用

    同样{0,} 表示的做用和 * 号相同

  1. + 代表 1 到多个
  2. * 代表 0 到多个
  3. 0个或者一个, 就是有没有都可以

修饰前面的正则

//案例: 字符串的html元素, 匹配出来里面所有的标签
const htmlElement = "<div><span>哈哈哈</span><h2>我是标题</h2></div>"
console.log(htmlElement.match(/<\/?[a-z][a-z0-9][a-z]?[a-z]*>/ig))
//这里的?代表了[a-z]存在0个或者1个都可以

8、贪婪( Greedy)和惰性( lazy)模式

Section titled “8、贪婪( Greedy)和惰性( lazy)模式”

默认情况下、正则表达式是贪婪模式,在获取一个区间的字符串,会获取满足最后一个和第一个出现的正则规则的符号之间的字符

const message = "我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》"
console.log(message.match(/.+/ig)) //返回所有匹配的数组
  • 这样的正则返回的是 [《黄金时代》和《沉默的大多数》、《一只特立独行的猪》]

    在第一个和”《 ” 最后一个 ”》” 之间的所有字符,返回一个元素

  • 而返回的 [《黄金时代》,《沉默的大多数》,《一只特立独行的猪》]

    而我们想要的是这种效果,就要切换为 lazy 模式

  • 我们可以在量词后面加一个问号 ‘?’ 来启用它

  • 所以匹配模式变为 ? 或 +?,甚至将 ’?’ 变为 ??*

注意:这里一定要放在量词的后面

Section titled “注意:这里一定要放在量词的后面”

不放在量词的后面表示无效

模式的一部分可以用括号括起来 (…),这称为“捕获组(capturing group)”。

  1. 它将括号视为一个整体;

    //表示abc的c有一到多个的字符串,至少存在一个
    info.match(/(abc+){1,}/ig)

    这里将 abc 当成一个单独项的字符来匹配,不加小括号分组的话表示的是 c 有 1 或者多个

  2. 它允许将匹配用括号括起来的一部分作为matchAll结果数组中的单独项,按照索引顺序排布;

对于更复杂的模式,计算括号很不方便。给括号(当前组)起个名字。

  • (?<自定义命名>)
const message = "我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》"
message.matchAll(/《(?<wyn>.+?)》/ig).next()
  • 命名组会放在数组中的 groups 属性里,可以通过 groups 属性获取对应的分组数据

    [
    0: "《黄金时代》"
    1: "黄金时代"
    //存放命名组数据
    groups: {wyn: '黄金时代'}
    index: 10
    input: "我最喜欢的两本书: 《黄金时代》和《沉默的大多数》、《一只特立独行的猪》"
    length: 2
    ]

用来排除一个捕获组

  • 当使用场景需要捕获组(括号)来表达一组应用量词,并且不希望它们的内容出现在结果中

  • 在捕获组内的开头添加 ?: 来排除组。

    console.log(info.match(/.(?:abc)/i));

or是正则表达式中的一个术语,实际上是一个简单的“或”。

  • 在正则表达式中,它用竖线 | 表示;

  • 通常会和捕获组一起来使用,在其中表示多个值;

    (123| 234 | 234) 和 | 在一起的时候也表示允许匹配多个值,与 [123] 的区别就是 集合表示的是多个单一的字符

5、重点注意:match 返回的类数组对象 0 索引是当前匹配的字符串

返回一个 boolean 值,正常匹配到返回true 否则返回 false

一个在字符串中执行查找匹配的 RegExp 方法,它返回一个数组

  • 注意:使用全局修饰符的时候同一个 regexp 实例要再次调用才会返回下一次的匹配

    相当于是一个迭代器

['i', index: 10, input: 'zhangsan lisi wangwu', groups: undefined]
//匹配到的字符
0: "i"
//分组属性
groups: undefined
//索引属性
index: 10
//整体字符串
input: "zhangsan lisi wangwu"
//length 属性
length: 1
[[Prototype]]: Array(0)

2. String中可以使用正则的方法(5个)

Section titled “2. String中可以使用正则的方法(5个)”

简但理解:match 主要返回的是对象,如果单一加g 或者多不加g都会返回不一样的效果

  • 一个在字符串中执行查找匹配的 String 方法,它返回一个数组 包含匹配的所有字符在未匹配到时会返回 null
  • 注意:这里使用全局描述符 g 话会返回单一字符串的结果数组(就是普通字符串数组)不加 g 的话返回的是 详细数据信息(有分组信息的)数组
  • 一个在字符串中执行查找所有匹配的 String 方法,它返回一个迭代器(iterator)
  • 正则表达式不能省略全局修饰符 g 会报错
  • 迭代器 value 是个数组 同 regexp.exec() 返回的数组
  • 迭代器也可以遍历 for…of

返回第一个匹配字符的索引 所以加不加 g 都无所谓

  • replacereplaceAll 的区别就是在正则表达式中添加了 g 修饰符

    replaceAll 参数如果是正则必须要添加 g 修饰符否则报错

    //这里的 regexp 可以不加 g 修饰符
    const temp = str.replaceAll(/cba/ig, "nba")
    //replaceAll这里的 regexp g 修饰符不加的话会报错 类型错误
    const newMessage2 = str.replaceAll(/\d+/ig, "")

使用 regexp 来分割转换为数组

  • 歌词文件每句歌词转换为此格式 {time: 24380, content: ‘我好想住你隔壁’}
// 将歌词文件字符格式,以/n 分割转换为字符串
const lyricList = arr.lrc.lyric.split(/\n/ig)
//这里以一句歌词为例
const newArr = ["[00:24.380]我好想住你隔壁"]
let regexp = /\[(\d{2,}):(\d{2,}).(\d{2,3})\]/i
lyricList.forEach(el => {
if(!el) return
//不加 g 返回的是详细数组
let time = el.match(regexp)
let minutes = time[1] * 60 * 1000
let second = time[2] * 1000
// 注意字符串的隐式转换,不然就是拼接了 time[3] * 1 要乘1 隐式转换number
let millisecond = time[3].length === 2 ? time[3] * 10 : time[3] * 1
let content = el.replace(regexp, "")
newArr.push({time: minutes + second + millisecond, content})
});
console.log(newArr)
  • 将时间转换为指定格式的字符串
const formatString = "yyyy-MM-dd hh-mm-ss"
function formatData(Unix, formatString) {
const data = new Data(Unix)
//(重点) 指定规则设置对应的正则和时间值
let rule = {
"y+": date.getFullYear(),
"M+": date.getMonth() + 1,
"d+": date.getDate(),
"h+": date.getHours(),
"m+": date.getMinutes(),
"s+": String(date.getSeconds()).padStart(2, "0")
}
for (const key in rule) {
if (Object.hasOwnProperty.call(rule, key)) {
const element = rule[key];
let regexp = new RegExp(key)
//用户设置了对应得格式。
if(regexp.test(formatString)) {
//循环替换
formatString = formatString.replace(regexp, element)
}
}
}
return formatString
}
console.log(formatData(new Date(), formatString))

https://c.runoob.com/front-end/854/