正则表达式规则及在JavaScript中使用的详细介绍

导读:本篇文章讲解 正则表达式规则及在JavaScript中使用的详细介绍,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

正则表达式

1. 什么是正则表达式?

我们先来看一下维基百科对正则表达式的解释:

  • 正则表达式(英语:Regular Expression,常简写为regex、regexp或RE),又称正则表示式、正则表示法、规则表达式、常规表示法,是计算机科学的一个概念;
  • 正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。
  • 许多程序设计语言都支持利用正则表达式进行字符串操作。

简单概况:正则表达式是一种字符串匹配利器,可以帮助我们搜索、获取、替代字符串;

在JavaScript中,正则表达式使用RegExp类来创建,也有对应的字面量的方式:

  • 正则表达式主要由两部分组成:规则(patterns)和修饰符(flags)
// 通过RegExp类创建
const re1 = new RegExp("hello", "i")
// 通过字面量的方式创建
const re2 = /hello/i

2. 正则表达式的使用方法

有了正则表达式我们要如何使用它呢?或者说我们在什么地方可以使用正则表达式

  • JavaScript中的正则表达式可以被用于 RegExp 的实例方法exec 和 test ;
方法 描述
exec 一个在字符串中执行查找匹配的 RegExp 方法,它返回一个数组(未匹配到则返回 null)。
test 一个在字符串中测试是否匹配的 RegExp 方法,它返回 true 或 false。

方法演示代码:

  • 1. exec方法

    // exec方法使用正则执行一个字符串
    const re1 = /abc/ig
    const message = "abc fhaBc opABc ABC uiaBC"
    
    // 返回一个数组
    console.log(re1.exec(message)) // ['abc', index: 0, input: 'abc fhaBc opABc ABC uiaBC', groups: undefined]
    
  • 2. test方法

    // test方法用于检测某一个字符串是否符合正则表达式的规则
    const re1 = /abc/ig
    const re2 = /aaa/ig
    const message = "abc fhaBc opABc ABC uiaBC"
    
    // 返回一个布尔类型
    console.log(re1.test(message)) // true
    console.log(re2.test(message)) // false
    
  • 也可以被用于字符串方法 : match、matchAll、replace、search 和 split 方法;

方法 描述
match 一个在字符串中执行查找匹配的 String 方法,它返回一个数组,在未匹配到时会返回 null。
matchAll 一个在字符串中执行查找所有匹配的 String 方法,它返回一个迭代器(iterator)。
search 一个在字符串中测试匹配的 String 方法,它返回匹配到的位置索引,或者在失败时返回-1。
replace 一个在字符串中执行查找匹配的 String 方法,并且使用替换字符串替换掉匹配到的子字符串。
split 一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中的 String 方法。

方法演示代码:

  • 1. match方法

    const re1 = /abc/ig
    const message = "abc fhaBc opABc ABC uiaBC"
    
    // 返回一个符合正则条件的字符串数组
    console.log(message.match(re1)) // ['abc', 'aBc', 'ABc', 'ABC', 'aBC']
    
  • 2. matchAll (matchAll正则表达式的修饰符必须加g)

    const re1 = /abc/ig
    const message = "abc fhaBc opABc ABC uiaBC"
    
    // 返回一个符合正则条件的字符串迭代器
    console.log(message.matchAll(re1)) // RegExpStringIterator {}
    
    // 返回迭代器意味着我们可以调用它的next方法
    const result = message.matchAll(re1)
    console.log(result.next()) // {value: Array(1), done: false}
    console.log(result.next()) // {value: Array(1), done: false}
    console.log(result.next()) // {value: Array(1), done: false}
    console.log(result.next()) // {value: Array(1), done: false}
    console.log(result.next()) // {value: Array(1), done: false}
    
  • 3. search方法

    const re1 = /abc/ig
    const message = "abc fhaBc opABc ABC uiaBC"
    
    // 返回匹配到的位置索引
    const result = message.search(re1)
    console.log(result) // 0
    
  • 4. replace方法

    const re1 = /abc/ig
    const message = "abc fhaBc opABc ABC uiaBC"
    
    // 将符合正则匹配规则的字符串替换为空
    const newMessage = message.replace(re1, "")
    console.log(newMessage) // fh op  ui
    
  • 5. split方法

    const re1 = /abc/ig
    const message = "abc fhaBc opABc ABC uiaBC"
    
    // 以符合正则匹配规则的字符串来切割成一个新的数组
    const result = message.split(re1)
    console.log(result) // ['', ' fh', ' op', ' ', ' ui', '']
    

3. 修饰符flag的使用

常见的修饰符

flag 含义
g 全部的,给我匹配全部的
i 忽略大小写
m 多行匹配

需求

获取一个字符串中所有的abc(无论大小写), 将一个字符串中的所有abc换成大写;

const message = "abc fhaBc opABc ABC uiaBC"

const newMessage = message.replace(/abc/ig, "ABC")
console.log(newMessage) // ABC fhABC opABC ABC uiABC

4. 正则表达式常见规则

4.1 字符类和反向类

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

字符 含义
\d 匹配数字:从 0 到 9 的字符。
\s 匹配空格符号:包括空格,制表符 \t,换行符 \n 和其他少数稀有字符,例如 \v,\f 和 \r。
\w “单字”字符:拉丁字母或数字或下划线 _。
.(点) 点 . 是一种特殊字符类,它与 “除换行符之外的任何字符” 匹配

演示代码:

  • 1. \d: 匹配数字

    // 单独一个 \d 只会匹配一个数字
    const re = /\d/ig
    const message = "abc123 fhaB24 op242ABc AB799C uia434BC35"
    
    const result = message.match(re)
    console.log(result) // ['1', '2', '3', '2', '4', '2', '4', '2', '7', '9', '9', '4', '3', '4', '3', '5']
    
    // \d+ 表示匹配一个或者多个数字
    const re = /\d+/ig
    const message = "abc123 fhaB24 op242ABc AB799C uia434BC35"
    
    const result = message.match(re)
    console.log(result) // ['123', '24', '242', '799', '434', '35']
    
  • 2. \s: 匹配空格符

    const re = /\s/ig
    const message = "abc123 fhaB24 op242ABc  AB799C uia434BC35"
    
    const result = message.match(re)
    console.log(result) // [' ', ' ', ' ', ' ', ' ']
    
  • 3. \w: 可以匹配大小写字母和数字以及下划线

    const re = /\w/ig
    const message = "Ab1_"
    
    const result = message.match(re)
    console.log(result) // ['A', 'b', '1', '_']
    
  • 4. ” . “: 匹配除换行符之外的所有字符

    const re = /./ig
    const message = "Ab1_@!#$%"
    
    const result = message.match(re)
    console.log(result) // ['A', 'b', '1', '_', '@', '!', '#', '$', '%']
    

反向类(Inverse classes)

  • \D 非数字:除 \d 以外的任何字符,例如字母。
  • \S 非空格符号:除 \s 以外的任何字符,例如字母。
  • \W 非单字字符:除 \w 以外的任何字符,例如非拉丁字母或空格。

4.2 锚点和词边界

符号 ^ 和符号 $ 在正则表达式中具有特殊的意义,它们被称为“锚点”。

  • 符号 ^ 匹配文本开头;

  • 符号 $ 匹配文本末尾;

    const message = "aAabBb"
    
    // 判断是否是aaa开头的
    if(/^aaa/i.test(message)) {
      console.log("是以aaa开头的")
    }
    
    // 判断是否是bbb结尾的
    if(/bbb$/i.test(message)) {
      console.log("是以bbb结尾的")
    }
    
    // 如果开头结尾都限制, 如下表示只能是匹配aaabbb(不分大小写)
    if(/^aaabbb$/i.test(message)) {
      console.log("满足匹配条件")
    }
    

词边界(Word boundary)

  • 词边界 \b 是一种检查,就像 ^ 和 $ 一样,它会检查字符串中的位置是否是词边界。
  • 词边界测试 \b 检查位置的一侧是否匹配 \w,而另一侧则不匹配 “\w”

在字符串 Hello, Java! 中,以下位置对应于 \b:

在这里插入图片描述

示例代码

  • 匹配下面字符串中的时间:

    // 匹配下面字符串中的时间
    const message = "now time 22:45, number is 123:456"
    
    // 不加词边界会将后面的数字也匹配
    const result1 = message.match(/\d\d:\d\d/g)
    console.log(result1) // ['22:45', '23:45']
    
    // 下面两个\b相当于是: 以词边界开头, 以词边界结尾
    const result2 = message.match(/\b\d\d:\d\d\b/g)
    console.log(result2) // ['22:45']
    

4.3 转义字符

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

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

示例代码:

  • 例如我们想要匹配字符串的”.“这个符号, 但是我们直接写”.”会匹配所有的字符, 那么这个时候就需要使用转义字符

    const re = /\./ig
    const message = "abc.def"
    
    const result = message.match(re)
    console.log(result) // ['.']
    

常见的需要转义的字符:

  • [] \ ^ $ . | ? * + ( )
  • 斜杠符号 ‘/’ 并不是一个特殊符号,但是在字面量正则表达式中也需要转义;

练习:匹配所有以.js结尾的文件名

const fileNames = ["aaa.js", "bbb.java", "ccc.html", "ddd.jsx", "eee.css", "fff.js"]

const newNames = []
for(const item of fileNames) {
  if(/\.js$/.test(item)) {
    newNames.push(item)
  }
}

console.log(newNames) // ['aaa.js', 'fff.js']

在webpack当中,匹配文件名时就是以这样的方式。

5. 集合和范围

有时候我们只要选择多个匹配字符的其中之一就可以:

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

集合(Sets):

  • 比如说,[eao] 意味着查找在 3 个字符 ‘a’、‘e’ 或者 `‘o’ 中的任意一个

范围(Ranges):

  • 方括号也可以包含字符范围;
  • 比如说,[a-z] 会匹配从 a 到 z 范围内的字母(小写),[0-5] 表示从 0 到 5 的数字;
  • [0-9A-F] 表示两个范围:但是它搜索一个字符,满足数字 0 到 9 或字母 A 到 F;
  • \d —— 和 [0-9] 相同;
  • \w —— 和 [a-zA-Z0-9_] 相同;

案例:匹配手机号码的前三位

手机号的规则:

  1. 第一位是1开头

  2. 第二位没有数字0、2和3

  3. 第三位任意数字

    const phoneStarts = ["130", "156", "120", "155", "180", "110"]
    // 第一位是1开头 第二位是4-9任意一个 第三位是任意一个数字
    const phoneStartRe = /^1[3-9]\d/
    const newPhoneStarts = phoneStarts.filter(item => phoneStartRe.test(item))
    console.log(newPhoneStarts) // ['130', '156', '155', '180']
    

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

  • 如下:

    // 匹配除0-9以外的, 类似\D
    const re1 = [^0-9]
    

6. 量词

假设我们有一个字符串 +7(903)-123-45-67,并且想要找到它包含的所有数字。

  • 因为它们的数量是不同的,所以我们需要给数量一个范围;
  • 用来形容我们所需要的数量的词被称为量词( Quantifiers )。

数量 {n}

  • 确切的位数:{5}
  • 某个范围的位数:{3,5}

缩写:

  • +: 代表“一个或多个”,相当于 {1,}
  • ?:代表“零个或一个”,相当于 {0,1}。换句话说,它使得符号变得可选;
  • *:代表“零个或多个”,相当于 {0,}。也就是说,这个字符可以多次出现或不出现;

案例:

  1. 匹配字符串 +7(903)-123-45-67中包含的所有数字

    const message = "+7(903)-123-45-67"
    const re = /\d+/g
    const result = message.match(re)
    console.log(result) // ['7', '903', '123', '45', '67']
    
  2. 匹配html的开始和结束标签

    const htmlElement = "<div><p>哈哈哈哈</p><span>呵呵呵呵</span><h2>标题</h2></div>"
    const re = /<\/?[a-z][a-z0-9]*>/ig
    const result = htmlElement.match(re)
    console.log(result) // ['<div>', '<p>', '</p>', '<span>', '</span>', '<h2>', '</h2>', '</div>']
    

7. 贪婪模式和惰性模式

如果我们有这样一个需求:匹配下面字符串中所有使用《》包裹的内容

const message = "有这么两本书:《你不知道的JavaScript》《C语言基础》"

默认情况下的匹配规则是查找到匹配的内容后,会继续向后查找,一直找到最后一个匹配的内容

  • 这种匹配的方式,我们称之为贪婪模式(Greedy)
const message = "有这么两本书:《你不知道的JavaScript》《C语言基础》"
const results = message.match(/《.+》/g)

// 如下 两本书匹配放在同一个字符串中
console.log(results) // ['《你不知道的JavaScript》《C语言基础》']

懒惰模式与贪婪模式中的是相反的

  • 只要获取到对应的内容后,就不再继续向后匹配;

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

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

const message = "有这么两本书:《你不知道的JavaScript》《C语言基础》"
// 使用惰性模式
const results = message.match(/《.+?》/g)
console.log(results) // ['《你不知道的JavaScript》', '《C语言基础》']

8. 捕获组

8.1 捕获组的基本介绍

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

这有两个作用:

  • 它允许将匹配的一部分作为结果数组中的单独项
  • 将括号视为一个整体

方法 str.match(regexp),如果 regexp 没有 g 标志,将查找第一个匹配并将它作为一个数组返回

  • 在索引 0 处:完全匹配。
  • 在索引 1 处:第一个括号的内容。
  • 在索引 2 处:第二个括号的内容。
  • …等等…

案例:我们用刚刚的案例举例,匹配《》包裹的内容, 不含《》符号

const message = "有这么两本书:《你不知道的JavaScript》《C语言基础》"
const results = message.match(/(《)(.+?)(》)/)
// 索引0处, 完全匹配
console.log(results[0]) // 《你不知道的JavaScript》
// 索引1处, 第一个括号内容
console.log(results[1]) // 《
// 索引2处, 第二个括号内容
console.log(results[2]) // 你不知道的JavaScript
// 索引3初, 第三个括号内容
console.log(results[3]) // 》

我们也可以使用matchAll方法, matchAll方法返回一个迭代器, 上面有讲过

const message = "有这么两本书:《你不知道的JavaScript》《C语言基础》"
const iterator = message.matchAll(/(《)(.+?)(》)/ig)

// 拿到第一本书
const firstBook = iterator.next()
// 索引0处, 完全匹配
console.log(firstBook.value[0]) // 《你不知道的JavaScript》
// 索引1处, 第一个括号内容
console.log(firstBook.value[1]) // 《
// 索引2处, 第二个括号内容
console.log(firstBook.value[2]) // 你不知道的JavaScript
// 索引3初, 第三个括号内容
console.log(firstBook.value[3]) // 》

// 拿到第二本书
const secondBook = iterator.next()
// 索引0处, 完全匹配
console.log(secondBook.value[0]) // 《C语言基础》
// 索引1处, 第一个括号内容
console.log(secondBook.value[1]) // 《
// 索引2处, 第二个括号内容
console.log(secondBook.value[2]) // C语言基础
// 索引3初, 第三个括号内容
console.log(secondBook.value[3]) // 》

8.2 捕获组的补充(了解)

命名组:

  • 用数字索引记录组很困难。
  • 对于更复杂的模式,计算括号很不方便。我们有一个更好的选择:给括号起个名字
  • 这是通过在<font color=‘cornflowerblue’。

非捕获组:

  • 用数字索引记录组很困难。

  • 对于更复杂的模式,计算括号很不方便。我们有一个更好的选择:给括号起个名字

  • 这是通过在开始括号之后立即放置 ?<name> 来完成的

    const message = "有这么两本书:《你不知道的JavaScript》《C语言基础》"
    const iterator = message.matchAll(/(《)(?<js>.+?)(》)/ig)
    // 获取第一本书
    const firstBook = iterator.next()
    // 在组里面获取命名组
    console.log(firstBook.value.groups.js) // 你不知道的JavaScript
    

非捕获组:

  • 有时我们需要括号才能正确应用量词,但我们不希望它们的内容出现在结果中

  • 可以通过在开头添加 ?: 来排除组

    const message = "有这么两本书:《你不知道的JavaScript》《C语言基础》"
    const iterator = message.matchAll(/(?:《)(?<js>.+?)(?:》)/ig)
    // 获取第一本书
    const firstBook = iterator.next()
    // 在组里面获取命名组
    console.log(firstBook.value[0]) //《你不知道的JavaScript》
    console.log(firstBook.value[1]) // 你不知道的JavaScript
    // 第一个小括号和第三个小括号的组被排除
    console.log(firstBook.value[2]) // undefined
    console.log(firstBook.value[3]) // undefined
    

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

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

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

    const message = "asabcabcjcbaabcdabclabccbakabcabcas"
    // 匹配abc或者cba
    const re = /(abc|cba){2,}/ig
    const result = message.match(re)
    console.log(result) // ['abcabc', 'cbaabc', 'abccba', 'abcabc']
    

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/120115.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!