正则表达式

  • 正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。
  • 在 JavaScript中,正则表达式也是对象 。
  • 通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式。

语法

定义正则表达式语法

  1. 字面量形式

    1
    let 变量名 = /表达式/
    • 其中,/ /是正则表达式字面量
    • object(复杂数据类型)
  2. 内置构造函数创建

    1
    2
    var res=new RegExp(‘abcd’)
    console.log(res) // /abcd/

判断是否有符合规则的字符串

test()方法:用来查看正则表达式与指定的字符串是否匹配。

例如:

image-20220908163255374

检查(查找)符合规则的字符串

exec() 方法:在一个指定字符串中执行一个搜索匹配。

例如:

image-20220908163433792

元字符

  • 普通字符

    大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。 也就是说普通字符只能够匹配字符串中与它们相同的字符。

  • 元字符(特殊字符)

    是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。

    • 比如,规定用户只能输入英文26个英文字母,普通字符的话 abcdefghijklm……
    • 但是换成元字符写法: [a-z]

边界符

正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符:

边界符 说明
^ 表示匹配行首的文本(以谁开始)
$ 表示匹配行尾的文本(以谁结束)

如果^$在一起,表示必须是精确匹配。

例如:

image-20220908163943056

量词

量词用来 设定某个模式出现的次数

量词 说明
* 重复零次或更多次
+ 重复一次或更多次
重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

注意:逗号左右量词千万不要出现空格

例如:

image-20220908164211679

image-20220908164224761

image-20220908164251792

字符类

[ ]匹配字符集合

后面的字符串只要包含 abc 中任意一个字符,都返回 true

例如:

image-20220908164401167

[ ]里面加上 - 连字符

表示一个范围,比如:

  • [a-z] 表示 az 26个英文字母都可以

  • [a-zA-Z] 表示大小写都可以

  • [0-9] 表示 0~9 的数字都可以

    image-20220908164628350

[ ] 里面加上 ^ 取反符号

比如:

  • [^a-z] 匹配除了小写字母以外的字符

  • 注意要写到中括号里面

. 匹配除换行符之外的任何单个字符

预定义字符

指的是某些常见模式的简写方式

预定类 说明
\d 匹配0-9之间的任一数字,相当于**[0-9]**
\D 匹配所有0-9以外的字符,相当于**[^0-9]**
\w 匹配任意的字母、数字和下划线,相当于**[A-Za-z0-9]**
\W 除所有字母、数字和下划线以外的字符,相当于**[^A-Za-z0-9_]**
\s 匹配空格(包括换行符、制表符、空格符等),相当于**[\t\r\n\v\f]**
\S 匹配非空格的字符,相当于**[^\t\r\n\v\f]**

比如:

image-20220908165321171

修饰符

修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等。

简单修饰符

语法:/表达式/修饰符

  • i 是单词 ignore 的缩写,正则匹配时字母不区分大小写

  • g 是单词 global 的缩写,匹配所有满足正则表达式的结果

比如:

image-20220908165508957

替换replace

语法:字符串.replace(/正则表达式/,'替换的文本')

正则的贪婪和非贪婪

贪婪(+)

1
2
3
const reg = /\d+/
//能捕获的最大长度
console.log(reg.exec('abc12345678abc')) // 12345678

非贪婪(?)

1
2
3
const reg = /\d+?/
//能捕获的最小长度
console.log(reg.exec('abc12345678abc')) // 1

??

1
2
3
const reg = /\d??/
//能捕获的最小长度
console.log(reg.exec('12345678abc')) // ''

{n,}? 获取 n 个

当 n 为 1 的时候,等价于+

当 n 为 0 的时候,等价于*

例子

  1. 获取开标签

    1
    2
    3
    4
    const str = '<div>你是什么呀</div>'
    //获取开标签
    const reg = /<.+?>/
    console.log(reg.exec(str)) //div
  2. 匹配的一个字符

    1
    2
    3
    4
    const reg = /abcd{2}/
    //是匹配前面一个字符
    console.log(reg.test('abcdabcd')) //false
    console.log(reg.test('abcdd')) //true

正则特殊字符

():一个整体

作用:1. 表示把 abcd 当作一个整体 2. 单独捕获

1
2
const reg = /(abcd){2}/
console.log(reg.test('abcdabcd')) //true

单独捕获的场景: 从左括号开始依次捕获,当作整体

1
2
const reg = /(\d+(\s+))\d+/
console.log(reg.exec('123 123'))

image-20220307215550475

不写小括号时

1
2
const reg = /\d+\s+\d+/
console.log(reg.exec('123 123'))

image-20220307220213888

(?:):整体捕获

|:占位或.表示左边或者右边都行,大部分时候和小括号连用.分开的是左边右边整个

1
2
3
4
const reg = /(abc|def)/
console.log(reg.test('abcd')) //true
console.log(reg.test('defa')) //true
console.log(reg.test('bcd')) //false

小练习:如果我们不加小括号。下列正则表示,以 abc 开头,以 def 结尾

1
2
3
4
5
6
7
8
9
10
const reg = /^abc|def$/
console.log(reg.test('abcd')) //true
console.log(reg.test('defa')) //false
console.log(reg.test('bcd')) //false
const reg = /^ab(c|d)ef$/
console.log(reg.test('abcd')) //false
console.log(reg.test('defa')) //false
console.log(reg.test('bcd')) //false
console.log(reg.test('abcef')) //true
console.log(reg.test('abdef')) //true

[]:表示包含中间的任意一个都行.占一个字符位置

1
2
3
4
5
const reg = /[abcd]/
console.log(reg.test('abcd')) //true
console.log(reg.test('d')) //true
console.log(reg.test('b')) //true
console.log(reg.test('a')) //true

[^]:表示包含中间的任意一个都行.占一个字符位置

1
2
3
4
5
6
//表示由一个字符组成,只要不是a.b,c,d中的都可以
const reg = /^[^abcd]$/
console.log(reg.test('a')) //false
console.log(reg.test('f')) //true
console.log(reg.test('b')) //false
console.log(reg.test('c')) //false

-:是使用在[]里面的符号,表示从哪一个字符到哪一个字符.,前提是他们的 Ascll 是连着的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//表示由一个字符组成,可以是0-9任意
const reg = /^[0-9]$/
console.log(reg.test('0')) //true
console.log(reg.test('1')) //true
console.log(reg.test('10')) //false
//表示由一个字符组成,可以是小写字母a-z任意
const reg = /^[a-z]$/
console.log(reg.test('a')) //true
console.log(reg.test('Z')) //false
console.log(reg.test('A')) //false

//表示由一个字符组成,可以是大写字母A-Z任意
const reg = /^[A-Z]$/
console.log(reg.test('a')) //false
console.log(reg.test('Z')) //true
console.log(reg.test('A')) //true

等价组合形式

  • [0-9a-zA-Z_]等价于\w
  • [^0-9a-za-z_]等价于\W
  • [0-9]等价于\d
  • [^0-9]等价于\D
  • [ ]等价于\s
  • [^ ]等价于\S

当我们在**[]里面的时候,点(.)**就表示一个点,不是上文所述的非换行任意字符

小练习

验证一个字符串,只能由字母数据下划线组成,6-12 位,不能以下划线开头

1
2
3
4
const reg = /^[0-9a-zA-Z]\w{5,11}$/
console.log(reg.test('123acd')) //true
console.log(reg.test('_11213sa')) //false
console.log(reg.test('q1w_dee')) //true

获取 HTML 标签里面的 text

1
2
3
4
const str = '<div>你是什么呀</div>'
//获取开标签
const reg = />(.+)</
console.log(reg.exec(str))

image-20220307223502689

正则表达式的预查

比如:“ES2015,ES2016,ES2017 都是 JavaScript 的语法标准”,我们想要查到 ES2015,ES2016

正向肯定预查(?=)

1
2
3
4
5
6
7
8
9
10
const reg = /^ES(?=2015|2016)/

//字符串ES2015,ES2016是可以的,但是我只捕获ES
console.log(reg.test('ES2015')) //true
console.log(reg.test('ES2016')) //true
console.log(reg.test('ES2017')) //false

console.log(reg.exec('ES2015'))
console.log(reg.exec('ES2016'))
console.log(reg.exec('ES2017'))

image-20220307225046423

正向否定预查(?!)

当我在捕获内容的时候,后面必须跟着不是我所指定的.我要的是 ES,但是后面不能跟 2015 和 2016

1
2
3
4
const reg = /ES(?!2015|2016)/
console.log(reg.exec('ES2015')) //null
console.log(reg.exec('ES2016')) //null
console.log(reg.exec('ES2017')) //false

image-20220307230022106

负向肯定预查(?<=)

后面是 ES,要求前面是 2015 或者 2016

1
2
3
4
const reg = /(?<=2015|2016)ES/
console.log(reg.exec('2015ES'))
console.log(reg.exec('2016ES'))
console.log(reg.exec('2017ES'))

image-20220307231814557

负向否定预查(?<!)

后面是 ES,要求前面不能是 2015 或者 2016

1
2
3
4
const reg = /(?<!2015|2016)ES/
console.log(reg.exec('2015ES'))
console.log(reg.exec('2016ES'))
console.log(reg.exec('2017ES'))

image-20220307232116753

重复出现符号

/num:num 是一个数字,表示正则第 num 个可被捕获的()。

这个可被捕获的小括号位置是什么,出现一份一模一样的内容

1
2
3
4
5
const reg = /(abc|def)\d+\1/
//前面是abc,后面就必须是abc
console.log(reg.test('abc123abc')) //true
console.log(reg.test('def123')) //false
console.log(reg.test('abc123def')) //false

邮箱匹配

名字:6-8 位,不能以_开头,只能是数字,字母下划线组成

只能是 qq 或者 163 或者 sins 邮箱

后缀只能是.com 或者.cn

1
2
3
const reg = /^[0-9a-zA-Z]\w{5,7}@(qq|163|sina)\.(com|cn)$/

console.log(reg.test('asdf11@qq.com'))

手机号

1
2
3
4
const reg = /^(?:\+86)?((133|158)\d{8})$/
const reg = /^[1][3,4,5,6.7,8,9][0-9]{9}$/

console.log(reg.exec('+8613378324567'))

image-20220307233743247

正则表达式标识符

标识符:是写在正则表达式外面,用来修饰整个正则表达式的

i:忽略大小写

g:全局

y:粘性全局

语法:/abcc/igy

1
New RegExp('abcd','igy)

i,忽略大小写

1
2
3
4
5
6
const arg = /abcd/
console.log(arg.test('abcd')) //true
console.log(arg.test('abcD')) //false

const arg = /abcd/i //忽略大小写
console.log(arg.test('abcd')) //false

g,全局匹配

因为我们匹配或者捕获都是只能捕获第一个

1
2
3
4
5
6
const arg = /abc/g //全局

// 捕获第二次,会从第一次的结束位开始查找
console.log(arg.exec('abc123abc123abc')) //0
console.log(arg.exec('abc123abc123abc')) //6
console.log(arg.exec('abc123abc123abc')) //12

image-20220308000037389

y,粘性全局

1
2
3
4
5
6
7
const arg = /abc/y //全局
// 捕获第二次,会从第一次的结束位开始查找
console.log(arg.exec('abc123abc123abc')) //0
console.log(arg.exec('abc123abc123abc')) //null
console.log(arg.exec('abc123abc123abc')) //0
// 必须要紧跟着
console.log(arg.exec('abcabcabc123abc')) //3

image-20220308000233640


参考文章:

https://donghuan1224.gitee.io/my-blog/2022/02/10/迷惑点合集/6_正则学习/#toc-heading-28