基本引用类型- RegExp

98 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

基本引用类型- RegExp

前言

正则表达式是很重要的。几乎每一门语言都会去支持正则表达式,ECMAScript 是通过 RegExp 类型来支持正则的。正则其实很常用,比如我们的路由是怎么去相应的匹配页面、在一段文字中提取我想要的文字等等都需要去使用正则。

正则匹配

  • 这个正则表达式的 pattern(模式)可以是简单活复杂的正则表达式(字符串、限定符、分组、向前查找反向引用)
  • 正则表达式可以带 0~多个 flags(标记)来控制正则表达式的行为。

匹配模式标记

  • g :全局模式,表示查找字符的全部内容
  • i :不区分大小写,表示查找匹配时忽略 pattern 和字符串的大小写
  • m :多行模式,表示查找到一行文本末尾会继续查找
  • y :粘附模式,表示只查找从 lastIndex 开始及之后的字符串。
  • u :Unicode 模式 ,启用 Unicode 匹配
  • s :doAll 模式,表示元字符,匹配任何字符(包括 \n \r)

标记也可以组合使用

let pattern = /at/gi

创建正则对象可以用字面量形式或者 RegExp 构造函数形式

字面量形式

也就是我们上面定义的这种

let pattern = /at/gi

元字符

\ 将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。如\n 匹配换行符
^ 匹配输入字符串的开始位置
$ 匹配输入字符串的结束位置
* 匹配前面的子表达式0次或多次
+ 匹配前面的子表达式1次或多次
?匹配前面的子表达式0次或1次
. 匹配换行符之外的任何单个字符
x|y 匹配 x 或 y
[xyz] 匹配所包含的任意一个字符
[^xyz] 匹配未包含的任意一个字符
[a-z] 匹配 a-z 的任意一个小写字母
\d 匹配一个数字字符 等价于 [0-9]
\D 匹配一个非数字字符 等价于[^0-9]
 
 
let pa = /[bc]at/i         匹配第一个"bat""cat" ,忽略大小写
let pa = /\[bc]at/i        匹配第一个"[bc]at" 忽略大小写
let pa = /.at/gi           匹配所有以"at"结尾的三字符组合,忽略大小写
let pa = /\.at/gi          匹配所有".at"忽略大小写

要想使用元字符,必须进行转义。

RegExp 构造函数

这种方式,传入的两个参数都是字符串

let pat = new RegExp("[bc]at","i")

元字符需要二次转意 \转义为 \,如 \n \n

字面量模式                   对应的字符串
 
/\[bc\]at/                  "\\[bc\\]at"
/\.at\                      "\\.at"
/name\/age/                 "name\\/age"
/\d.\d{1,2}/                "\\d.\\d{1,2}" 
/\w\\hello\\123/            "\\w\\\\hello\\\\123"

一、 RegExp 实例属性

这些属性可以全面了解正则表达式的信息,但是实际开发并不常用。比如我不需要知道正则表达式中是否使用了 g。

- global:布尔值,表示是否设置了 g 标记。

- ignoreCase:布尔值,表示是否设置了 i 标记。

- unicode:布尔值,表示是否设置了 u 标记。

- sticky:布尔值,表示是否设置了 y 标记。

- lastIndex:整数,表示在源字符串中下一次搜索的开始位置,始终从 0 开始。

- multiline:布尔值,表示是否设置了 m 标记。

- dotAll:布尔值,表示是否设置了 s 标记。

- source:正则表达式的字面量字符串(不是传给构造函数的模式字符串),没有开头和结尾的

  斜杠。

- flags:正则表达式的标记字符串。始终以字面量而非传入构造函数的字符串模式形式返回(没有前后斜杠)。

二、 RegExp 实例方法

这里我们介绍两个方法 exec() 和 test()

exec()

参数:要应用模式的字符串

需求:内部的匹配项"and baby",内部的 "and dad" 或 "and dad and bay"

let txt ="mom and dad and baby"
// 注意空格
let pattern = /mom( and dad( and baby)?)?/gi
let match = pattern.exec(txt)
// ['mom and dad and baby', ' and dad and baby', ' and baby', index: 0, input: 'mom and dad and baby', groups: undefined]

  • match[0]: 要查找的字符串
  • match[1]: 匹配的第一个字符串
  • match[2]: 匹配的第二个字符串(当匹配条件是多个的时候)
  • match["input"]: 要查找的字符串
  • match["index"]: 匹配到字符串的索引

思考一下 🤔

为什么这个数组 有字符串 还有键值对?

我这么定义是错的?那这还是数组吗?

let arr = [1,2,"test":11// Uncaught SyntaxError: Unexpected token ':'

没错这是一个普通数组,已分配了某些其他属性。由于数组是对象,因此它们除了通常的数字索引外还可以具有任意键值对,尽管您几乎永远都不会在普通的干净代码中看到这一点(正则表达式匹配是唯一可以想到的数组对象所在的位置其他非标准属性)。

其实可以像下面的方法定义,就得到了类似的数组。

let arr = [1]
arr.input = "test" // [1, 2, input: 'test']

全局标记 g

全局匹配究竟是什么意思?即使 exec(),使用了全局匹配,返回的结果还是相同的啊?

let text = "cat, bat, sat, fat"
 
let nogpattern = /.at/
// ['cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined]
nopattern.exec(text) 
 
// ['cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined]
let havegpattern = /.at/g
havegpattern.exec(text)

这是因为需要再次调用 exec(),它才会再向下寻找。这时候才能体现出 g 的作用

没使用 g

let text = "cat, bat, sat, fat"
let nog = /.at/
nog.exec(text) // ['cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined]
console.log(nog.lastIndex)  // 0 最后匹配到的索引
nog.exec(text) //['cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined]
console.log(nog.lastIndex)  // 0

使用 g

let text = "cat, bat, sat, fat"
let haveg = /.at/g // ['cat', index: 0, input: 'cat, bat, sat, fat', groups: undefined]
console.log(haveg.lastIndex)   // 0
haveg.exec(text) // ['bat', index: 5, input: 'cat, bat, sat, fat', groups: undefined]
console.log(haveg.lastIndex)  // 8

粘附标记 y

只查找从 lastIndex 开始和以后的字符串

let text = "_aa_a"
let pattern = /_a+/y
pattern.exec(text) // ['_aa', index: 0, input: '_aa_a', groups: undefined]

y

但是 我们想匹配 aa 或 a 返回的就是 null。因为从 lastIndex(0)开始寻找 。它找的字符串是

[" "," a","aa"," aa "," aa_a"] 也就是从下标为 0 开始的所有排列租户,

let text = "_aa_a"
let pattern = /a+/y   
pattern.exec(text)          //null
console.log(text.lastIndex) // 0

如果重新定义 pattern 的 lastIndex 则就可以找到

pattern.lastIndex = 1
pattern.exec(text)          // pattern.exec(text)          //null

g 而如果是 g,则找的是[" "," a","aa"," aa "," aaa","a","aa","aa","aaa","a","a","aa"," ","_a","a"] 也就是所有可能出现的排列组合。

test()

这个方法用于校验,模式是否匹配。返回 true 或 false

let a = "_aa_a"
let pattern = /_a+/g
pattern.test(a)            // true

toLocaleString() 和 toString()

let pattern = new RegExp("\\[bc\\]at","gi");
pattern.toString()         //         '/\[bc\]at/gi'
pattern.toLocaleString()   //         '/\[bc\]at/gi'

valueof()

返回正则表达式本身

三、 RegExp 构造函数属性

通过以下属性可以提取出与 exec()和 test()执行的操作相关信息

  • input  缩写 $_ 最后搜索的字符串
  • lastMatch 缩写 $&  最后匹配的文本
  • lastParen 缩写 $+  最后匹配的捕获组
  • leftContext  缩写 $` input 字符串中出现在 lastMatch 前面的文本
  • rightContext 缩写 $' input 字符串中出现在 lastMatch 后面的文本
let text = "this has been a short summer";
let pattern = /(.)hort/g
if(pattern.test(text)){
   console.log(RegExp.input);        // this has been a short summerh'n'm'n
   console.log(RegExp.$_);          // 同上
   console.log(RegExp.leftContext);   // tis has been a
   console.log(RegExp["$`"])          // 同上
   console.log(RegExp.rightContext);  // summer
   console.log(RegExp.lastMatch);    // short
   console.log(RegExp.lastParen);    // s
}

总结:   如果有什么不同的想法,可以在评论区留言,大家一起学习呀~ 最后如果这篇文章对您有帮助的话,请一件三连给作者一点点支持,谢谢啦!