正则表达式是用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。这些模式被用于 RegExpexectest 办法, 以及 StringmatchmatchAllreplacesearchsplit 办法。

正则的用意

正则表达式是匹配模式,要么匹配字符串,要么匹配地位

正则表达式是匹配模式,要么匹配字符串,要么匹配地位

正则表达式是匹配模式,要么匹配字符串,要么匹配地位

正则的创立

  • 形式一:字面量的创立

    const reg = //
  • 形式二:构造函数

    const reg = new RegExp()

补充

  1. 字面量是罕用的形式。
  2. 字面量创立构造函数的创立 是存在区别的

    // eg:const num = 12.34// 字面量const reg = /\d+.\d+/ // 构造函数const reg = new RegExp('\d+.\d+')

    reg 的 正则字符串是一样的,然而它们代表一样的意思吗?不是

    先看一段代码:

    console.log('\') // 报错 Javascript: unterminated string literalconsole.log('\d') // d

    在这里 \,在JS解析的时候是有非凡意义的。

    所以下面的构造函数形式的创立:

    const reg = new RegExp('\d+.\d+')  // d+.d+  匹配的d 这个字符// 须要本义const reg = new RegExp('\d+\.\d+')

    这种写法挺麻烦的,所以举荐应用 字面量的写法。

正则的原子

原子是正则表达式的最根本的组成单位,而且在每个模式中起码蕴含一个原子。

原子分为可见原子和不可见原子。

  • 可见原子: Unicode编码表中键盘输入肉眼可见的字符。
  • 不可见原子: Unicode编码表中键盘输入肉眼不可见的字符,如空格,制表符。

通用字符类型:

\d 匹配0-9任意一个数字[0-9]\D 除了数字以外的任意一个字符匹配[^0-9]\w 数字 字母 下划线匹配[a-zA-Z0-9]\W 除了数字 字母 下划线以外的任意一个字符[^a-zA-Z0-9]\s 与任意一个空白字符匹配\S 与任意一个空白字符意外的字符匹配[^\n\f\r\t\v]\f 换页字符;\n 换行字符;\r 回车字符;\t 制表符;\v 垂直制表符;

正则的特殊字符

开始(^) 和 完结($

对匹配的做开始的限定和完结的限定

const reg = /abc/  // abc aabc abcabc这些都是匹配胜利const reg = /^abc$/  // 只能

转义字符(\

\这个无论是在 正则还是在其余的中央都有着非凡的意义。

正则中有跟多的符号是有意义的,如果想要匹配他们都是须要本义的

\ ( ) [ ] ^ $ * + ? 这些符号都是有着本人各自的意义,上面会顺次介绍

const str = '()[]^$*+?'   // 这是一个字符串const reg = /\(\)\[\]\^\$\*\+\?/  // 大量的应用本义

或(|

左右两边看成一个整体,满足其中一个就行

const reg = /abc|acc/  // 匹配abc或者acc

点元字符(.

匹配除\n之外的任何单个字符。

 let str = `      james      kobe      `console.log(str.match(/.+/)) // '    james'

. 基本上都匹配了所有。那么匹配全副该怎么写呢?

// 匹配所有const reg = /[\d\D]+/const reg = /[\s\S]+/const reg = /.+/s  // s模式 

正则的量词(* + ?

{m,n} : 匹配m到n个字符,都是数字,还能够写成{m,}: m到有限个

const reg = /d{2,4}/   // 匹配d的数量为2到4个

*: 0个到无穷个 等价于 {0,}

const reg = /d*/

+: 1个到无穷个 等价于 {1,}

const reg = /d+/

?: 1个或者0个

const reg = /d?/

留神: * + ? {m,n} 它们都是贪心模式,上面会介绍。

原子表([]

[]满足其中的一个内容

const reg = /[abc]/  // a b c ab 都满足  

区间匹配

[0-9]   // 匹配0-9的数字[a-z]   // 匹配a-z的小写字母[A-Z]   // 匹配A-Z的大写字母

取反

[^abc]  // 匹配除了abc以外的字符

这里 ^ 尽管跟开始字符是一样的,然而示意的意义不一样。这里的 ^ 是在 []应用。

不解析字符

[.()+]  // 在原子表中,它们都是单纯的字符

原子组(()

() 与 原子表[]不同,()会把其中的内容看成一个整体。

const dom = `<h1>copyer</h1>`const reg = /^<h([1-6])>[\s\S]*</h([1-6])>$/i// 等价于const reg1 = /^<h([1-6])>[\s\S]*</\1>$/

([1-6])看成一个整体,就是为了匹配 h1~h6的标签

在第一个正则中,匹配开始标签完结标签,就会写两次的([1-6]),看起来是比拟麻烦的

1、组名

组名: 就是为了下面反复写的问题。

从左到右,顺次找出原子组(),排在第几个,就应用\num就行了;

比方: ([1-6]) 排在原子组的第二个,那么应用\2就能够了。

简略记忆: 只有判断了是原子组,就数 ( 从左到右排在第几个

2、嵌套组

// 匹配urlconst url = 'http://www.baidu.com'const reg = /^https?://[\w]+.[\w]+.(com|cn)$/console.log(url.match(reg))

match办法 前面也会总结

[    0:"http://www.baidu.com"    1: "com"    groups: undefined    index: 0    input: "http://www.baidu.com"]

数组第一个,就是匹配到的字符串

如果有原子组的应用,匹配到的后果,就会顺次放在第一个的前面

3、不记录组

下面不是对com 组提取进去了嘛,如果不想要记录该怎么做呢?

const reg = /^https?://[\w]+.[\w]+.(?:com|cn)$/

在原子组中: 应用?: 就不会记录在组中

(?:com|cn) ?:就是放在最开始

4、组的理论应用场景

给一个dom节点字符串,拿取外面的内容

let str = '<h1>copyer</h1>'const reg = /<h([1-6])>(.*)</h([1-6])>/console.log(str.match(reg)[2])

下面应用了三个原子组: ([1-6]) (.*) ([1-6])

这个三个都是push到数组中,内容就是第二个原子组,所以,咱们取下标为 2,就能够拿到内容了

正则的贪心模式

在下面,晓得了正则的量词(* + ? 的根本应用,然而呢,它们还是有一种个性: 贪心

何为贪心?

const str = 'aaaaaa'const reg = /a+/console.log(str.match(reg))  // aaaaaa

只有在条件的满足范畴内,能匹配到多少就是多少,贪心思维

那么怎么阻止贪心呢?

正则量词前面增加一个?

const str = 'aaaaaa'const reg = /a+?/console.log(str.match(reg))  // a

*? +? ?? {m,n}? 相似这种组合

正则的属性lastIndex

lastIndex从字面了解:最初一个索引值。实际上,它的意思是正则表达式开始下一次查找的索引地位

lastIndex 第一次的时候总是为0的,

第一次查找完了的时候会把lastIndex的值设为匹配到得字符串的最初一个字符的索引地位加1

const str = 'aaa_aa_aaaa'const reg_g = /a+/gconsole.log(reg_g.lastIndex) // 0  默认值console.log(reg_g.exec(str)) // aaaconsole.log(reg_g.lastIndex) // 3 上次匹配aaa 下标值为2,在下面的一次加 1,所以为3console.log(reg_g.exec(str)) // 所以这次匹配是在 下标为3的地位开始匹配

如果没有匹配到的话,lastIndex 就会从新置为 0

重要事项:不具备标记 g 和不示意全局模式的 RegExp 对象不能应用 lastIndex 属性。

前面,如同y修饰符也反对了。

lastIndex 是个 可读可写的属性

正则的修饰符

s修饰符

/s 示意将字符串视为单行来匹配 。

const dom = `  <h1>123</h1>  `;const reg = /.+/s;console.log(dom.match(reg));

s模式,会把字符串看一行来解析

[    0: "\n      <h1>123</h1>\n      "    groups: undefined    index: 0    input: "\n      <h1>123</h1>\n      "]

\n就解析进去了

i修饰符

正则是辨别大小写的,如果是在i模式下,就不辨别大小写了

g修饰符

全局匹配。

个别状况下,没有量词的状况下,匹配到一个,就不会持续匹配上来了。如果增加了 \g ,就会始终匹配上来满足条件的。

y修饰符

y 修饰符的作用与 g 修饰符相似,也是全局匹配,后一次匹配都从上一次匹配胜利的下一个地位开始。

不同之处:g 修饰符只有残余地位中存在匹配就可,而 y 修饰符确保匹配必须从残余的第一个地位开始

在这里,了解 y修饰符g修饰符 须要了解下面的lastIndex 正则属性

实例:

const str = 'aaa_aa_aaaa'const reg_g = /a+/gconst reg_y = /a+/yconsole.log('第一次')console.log(reg_g.lastIndex) // 0console.log(reg_y.lastIndex) // 0console.log(reg_g.exec(str)) // aaaconsole.log(reg_y.exec(str)) // aaaconsole.log('第二次')console.log(reg_g.lastIndex) // 3console.log(reg_y.lastIndex) // 3console.log(reg_g.exec(str)) // aaconsole.log(reg_y.exec(str)) // nullconsole.log('第三次')console.log(reg_g.lastIndex) // 6console.log(reg_y.lastIndex) // 0console.log(reg_g.exec(str)) // aaaaconsole.log(reg_y.exec(str)) // aaa

第一次, y修饰符g修饰符是一样的, lastIndex 都从 0 变成了 3

第二次,g修饰符 能够持续匹配前面的残余字符 aa ,所以lastIndex从 3 变成了 6

然而 y修饰符 须要的是残余字符 的第一个须要满足,很显然第二次的残余字符是不满足的,所以 匹配的值为 nulllastIndex 也从 重置了,变成 0

第三次,y修饰符有从新开始匹配。

u修饰符

正则的办法

字符串的办法

match()

语法:

str.match(regexp)

参数:

一个正则表达式对象。如果传入一个非正则表达式对象,则会隐式地应用 new RegExp(obj) 将其转换为一个 RegExp 。如果你没有给出任何参数并间接应用match() 办法 ,你将会失去一 个蕴含空字符串的 Array :[""] 。

返回值:

  • 如果有g 修饰符,则返回所有匹配的信息,不会返回捕捉值
  • 如果没有g修饰符,则返回一个残缺以及相干的捕捉值。

示例:

// 状况一: 存在g修饰符const str = "copyer";console.log(str.match(/c/g));    // ['c']// 状况二: 不存在g修饰符const str = "copyer";console.log(str.match(/c/));// 残缺的信息[    0: "c" // 捕捉值    groups: undefined    index: 0    input: "copyer"]

matchAll()

语法:

str.matchAll(regexp)

参数:

正则表达式对象。如果所传参数不是一个正则表达式对象,则会隐式地应用 new RegExp(obj) 将其转换为一个 RegExp

RegExp必须是设置了全局模式g的模式,否则会抛出异样TypeError

返回值:

一个迭代器

实例:

const str = "abaca";const matchs = str.matchAll(/a/g)  // 必须是全局模式// 返回值是一个迭代对象,应用for...of遍历for(let key of matchs) {    console.log(key)}// ['a', index: 0, input: 'abaca', groups: undefined]// ['a', index: 2, input: 'abaca', groups: undefined]// ['a', index: 4, input: 'abaca', groups: undefined]

这里获取所有捕捉值的办法。然而在matchAll()呈现之前,是通过正则办法 exec()来实现同样的目标。在上面会介绍到。

replace()

语法:

str.replace(regexp|substr, newSubStr|function)

参数:

  • regexp(pattern)

    一个RegExp 对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉。

  • substr(pattern)

    一个将被 newSubStr 替换的 字符串。其被视为一整个字符串,而不是一个正则表达式。仅第一个匹配项会被替换。

  • newSubStr (replacement)

    用于替换掉第一个参数在原字符串中的匹配局部的字符串。该字符串中能够内插一些非凡的变量名。

  • function (replacement)

    一个用来创立新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的后果。

返回值:

不扭转原来的字符串,会返回一个新的字符串

实例:

// 状况一: 参数为字符串:参数看为一个整体,匹配到的第一项会被替换const str = "abaca";const newStr = str.replace('a', 'f')console.log(newStr) // fbaca// 状况二: 参数为正则:匹配到的字符被新的字符串替换const str = "abaca";const newStr = str.replace(/a/g, 'f')console.log(newStr) // fbfcf// 状况三: 第二个参数为一个函数,返回的字符串用来替换const str = "abaca";const newStr = str.replace(/a/g, () => {    return '$#'})console.log(newStr)

当然,这个函数不是这么简略,还有其余的用法。

search()

语法:

str.search(regexp)

参数:

一个正则表达式(regular expression)对象。如果传入一个非正则表达式对象 regexp,则会应用 new RegExp(regexp) 隐式地将其转换为正则表达式对象。

返回值:

如果匹配胜利,则 search() 返回正则表达式在字符串中首次匹配项的索引;否则,返回 -1

实例:

const str = "abaca";console.log(str.search(/[b]/g))    // 1console.log(str.search(/[d]/g))    // -1

split()

语法:

str.split([separator [, limit]])

参数:

  • separator

    指定示意每个拆分应产生的点的字符串。separator 能够是一个字符串或正则表达式。 如果纯文本分隔符蕴含多个字符,则必须找到整个字符串来示意宰割点。如果在str中省略或不呈现分隔符,则返回的数组蕴含一个由整个字符串组成的元素。如果分隔符为空字符串,则将str原字符串中每个字符的数组模式返回。

  • limit

    一个整数,限定返回的宰割片段数量。当提供此参数时,split 办法会在指定分隔符的每次呈现时宰割该字符串,但在限度条目已放入数组时进行。如果在达到指定限度之前达到字符串的开端,它可能依然蕴含少于限度的条目。新数组中不返回剩下的文本。

返回值:

返回源字符串以分隔符呈现地位分隔而成的一个 Array

实例:

const str = "abaca";console.log(str.split('c'))     // ['aba', 'a']console.log(str.split('@'))     // ['abaca']console.log(str.split(''))      // ['a', 'b', 'a', 'c', 'a']console.log(str.split('a'))     // ['', 'b', 'c', '']console.log(str.split('', 3))   // ['a', 'b', 'a']

形容:

  1. 找到分隔符后,将其从字符串中删除,并将子字符串的数组返回。
  2. 如果没有找到或者省略了分隔符,则该数组蕴含一个由整个字符串组成的元素。
  3. 如果分隔符为空字符串,则将str转换为字符数组。
  4. 如果分隔符呈现在字符串的开始或结尾,或两者都离开,别离以空字符串结尾,结尾或两者开始和完结。

留神:

如果分隔符是蕴含捕捉括号的正则表达式,则每次分隔符匹配时,捕捉括号的后果(包含任何未定义的后果)将被拼接到输入数组中。然而,并不是所有浏览器都反对此性能。

const str = "abaca";console.log(str.split(/(a)/))    // ['', 'a', 'b', 'a', 'c', 'a', '']

正则的办法

test()

语法:

regexObj.test(str)

参数:

  • str

    用来与正则表达式匹配的字符串

返回值:

如果正则表达式与指定的字符串匹配 ,返回true;否则false

实例:

let str = 'hello world!';let result = /^hello/.test(str);console.log(result);  // true

exec()

语法:

regexObj.exec(str)

参数:

  • str

    要匹配正则表达式的字符串。

返回值:

如果匹配胜利,exec() 办法返回一个数组(蕴含额定的属性 indexinput ),并更新正则表达式对象的 lastIndex属性。

齐全匹配胜利的文本将作为返回数组的第一项,从第二项起,后续每项都对应正则表达式内捕捉括号里匹配胜利的文本。

如果匹配失败,exec() 办法返回 null,并将 lastIndex 重置为 0 。

实例:

const str = "abaca";const reg = /a/gconsole.log(reg.lastIndex)  // 0console.log(reg.exec(str))  // ['a', index: 0, input: 'abaca', groups: undefined]console.log(reg.lastIndex)  // 1

lastIndex会被更新。
获取全副的匹配信息:

let str = "abaca";let reg = /a/g;let result;while ((result = reg.exec(str)) != null) {    console.log(result)}// ['a', index: 0, input: 'abaca', groups: undefined]// ['a', index: 2, input: 'abaca', groups: undefined]// ['a', index: 4, input: 'abaca', groups: undefined]

谬误写法:

let str = "abaca";let reg = /a/g;let result;while (reg.exec(str) !== null) {    console.log(result)}
正告: 不要把正则表达式字面量(或者RegExp结构器)放在 while 条件表达式里。因为每次迭代时 lastIndex 的属性都被重置,如果匹配,将会造成一个死循环。并且要确保应用了'g'标记来进行全局的匹配,否则同样会造成死循环。

正则的断言

正后行断言(?=

前面的内容,满足后面的条件

实例:

str='我有一只铅笔,我有一只钢笔',把铅笔后面的一只,换成2只

let str = "我有一只铅笔,我有一只钢笔";const reg = /一只(?=铅笔)/gconst newStr = str.replace(reg, '两只')console.log(newStr) // 我有两只铅笔,我有一只钢笔

了解:

就看成是条件就行了,前面的内容 是否等于 '匹配的内容'。

在下面的例子中,想把一只改成两只,全局搜寻的话,就会搜寻出两个,咱们只须要匹配铅笔的那一个,所以 判断条件是否等于(?= 铅笔就行了

负后行断言(?!=

前面的内容,不满足后面的条件

实例:

let str = "我有一只铅笔,我有一只钢笔";const reg = /一只(?!钢笔)/gconst newStr = str.replace(reg, '两只')console.log(newStr) // 我有两只铅笔,我有一只钢笔

取反即可

正后发断言(?<=

后面的内容,满足前面的条件

实例:

let str = "我有一个大爸和二爸";const reg = /(?<=大)爸/gconst newStr = str.replace(reg, '爷')console.log(newStr) // 我有一个大爷和二爸

大爸 和 二爸中的大爸的爸改成爷(只是举例,其余形式更加的简略)

负后发断言(?<!

后面的内容,不满足前面的条件

实例:

let str = "我有一个大爸和二爸";const reg = /(?<!二)爸/gconst newStr = str.replace(reg, '爷')console.log(newStr) // 我有一个大爷和二爸

意思跟下面差不多

总结

断言:就看成条件

  • 后行: 就是前面的内容须要满足的条件 /表达式(条件)/ 条件是写在前面的

<!---->

  • 后发: 就是后面的内容须要满足的条件/(条件)/表达式 条件是写在后面的

留神:

应用了小括号,然而不能看成是原子组

总结

花了两天的工夫,从头学习了一遍正则的根本语法。当然,在理论实际中,还是须要积攒的。

如果下面的内容有误,请提出来,多谢指教。