共计 2911 个字符,预计需要花费 8 分钟才能阅读完成。
先简略看几个罕用根底标识符
^ 匹配一个输出或一行的结尾,
/^a/
// 匹配 "an A",而不匹配 "An a"
$ 匹配一个输出或一行的结尾
/a$/
// 匹配 "An a",而不匹配 "an A"
* 匹配后面元字符 0 次或屡次
/ba*/
// 匹配 b,ba,baa,baaa,...
+ 匹配后面元字符 1 次或屡次
/ba+/
// 匹配 ba,baa,baaa,...
? 匹配后面元字符 0 次或 1 次
/ba?/
// 匹配 b,ba
(x) // 匹配 x 保留 x 在名为 $1...$9 的变量中
x|y // 匹配 x 或 y
{n} // 准确匹配 n 次
{n,} // 匹配 n 次以上
{n,m} // 匹配 n - m 次
[xyz] // 字符集,匹配这个汇合中的任一一个字符(或元字符),匹配 x,y,z
[^xyz] // 不匹配这个汇合中的任何一个字符
正则表达式 (Regular Expression) 其实是一门工具,通过字符串模式匹配,实现搜寻和替换性能。
它起源于 20 世纪 50 年代科学家在数学畛域做的一些钻研工作,起初才被引入到计算机领域中。
从它的命名咱们能够晓得,它是一种用来形容规定的表达式。而它的底层原理也非常简略,就是应用 状态机 的思维进行模式匹配。
这里先不细纠概念,罕用的办法属性,文档 mdn 什么都有,也不纠结,直奔主题。
子表达式
子表达式 (Reg) 具备独立的匹配性能,保留独立的匹配后果
-
作为独立单元能够应用 *+?{n,m}等量词
/(ab)?c)/ // 匹配 c 或者 abc
-
作为子模式能够独立解决,并且保留匹配后果子串, 可通过 RegExp.$1,…$n 拜访
var re = /(\w+)\s(\w+)/; var str = "John Smith"; var newstr = str.replace(re, "$2, $1"); console.log(newstr); // Smith, John
以下 RegExp 属性,不是 w3c 规范,不过大部浏览器反对
RegExp 属性 形容 $n 第 n 个子表达式匹配的字符串, 只有 1 -9 $& 最初匹配到的字符串,RegExp.lastMatch 别名 $’ 最新匹配的右侧子串,RegExp.rightContext 别名 $` 最新匹配的左侧子串,RegExp.leftContext 别名 $+ 匹配到的最初一个子串,RegExp.lastParen 别名 $_ 被匹配胜利的原字符串,RegExp.input 别名 对应 replace 函数中拜访正则后果的参数
变量名 形容 $n 插入第 n 个子表达式匹配的字符串, 只有 1 -99 $& 插入匹配的子串 $’ 插入以后匹配的子串左边的内容 $` 插入以后匹配的子串右边的内容 $<name> 匹配 [Name] 具名子表达式的字符串 -
回溯援用 (反向援用), 模式的前面局部援用后面子表达式曾经匹配到的子字符串
通过反斜杠 \ 加数字来实现的。数字代表子表达式在该正则表达式中的程序。例如: \1 援用的是 第一 个子表达式的 匹配后果是 匹配后果 不是匹配模式
var s = "<h1>title<h1><p>text<p>"; var r = /(<\/?\w+>).*\1/g; // 相当于 /(<\/?\w+>).*(<h1>|<p>)/g // 再加 (<\/?\w+>) 匹配后果 === (<h1>|<p>)匹配后果 var a = s.match(r); // 返回数组["<h1>title<h1>","<p>text<p>"]
子表达式的高级模式
非捕捉模式, 匹配后果不会保留
/(?:\w+)\s(\w+)/
// ?: 标识非捕捉
// $1 从第二个子表达式开始计算
命名捕捉,这个用的较少
var re = /(?<myName>\w+)\s(\w+)/;
console.log("John Smith".match(re));
// (?<Name>x)
// 匹配后果保留在匹配项的 groups 属性中
断言
断言用来限度正则匹配的边界。
其实 ^,&,\b,\B 也是断言。
- ^ 对应字符串结尾
- & 字符串结尾
- \b 单词边界
- \B 非单词边界
这里次要说其余四种断言
- 后行断言,/x(?=y)/ y 在前面追随 x 的时候匹配 x
- 后行否定断言,/x(?!y)/ y 没有在前面追随 x 的时候匹配 x
- 后行断言,/(?<=y)x/ y 在 x 后面紧随的时候匹配 x
-
后行否定断言,/(?<!y)x/ y 没有在 x 后面紧随的时候匹配 x
// 后行断言 let regex = /First(?= test)/g; console.log('First test'.match(regex)); // ['First'] // 后行否定断言 // /\d+(?!\.)/ 匹配没有被小数点追随且至多有一位的数字。/\d+(?!\.)/.exec('3.141') 匹配 "141" 而不是 "3" console.log(/\d+(?!\.)/g.exec('3.141')); // ['141', index: 2, input: '3.141'] // abc 前面不能追随 de let reg = /abc(?!de)/; reg.test('abcdefg'); // false; reg.test('abcd'); // true; reg.test('abcabc'); // true;
正则表达式的三种模式
在应用润饰匹配次数的特殊符号时,有几种示意办法能够使同一个表达式可能匹配不同的次数,比方:”{m,n}”, “{m,}”, “?”, “*”, “+”,具体匹配的次数随被匹配的字符串而定。
-
贪心模式
贪心模式总是尽可能多的匹配var regex = /\d{2,5}/g; var string = "123 1234 12345 123456"; console.log(string.match(regex) ); // => ["123", "1234", "12345", "12345"]
-
懈怠模式
在润饰匹配次数的特殊符号后再加上一个 “?” 号,则能够使匹配次数不定的表达式尽可能少的匹配,使可匹配可不匹配的表达式,尽可能的 “ 不匹配 ”var regex = /\d{2,5}?/g; var string = "123 1234 12345 123456"; console.log(string.match(regex) ); // => ["12", "12", "34", "12", "34", "12", "34", "56"] 其中 /\d{2,5}?/ 示意,尽管 2 到 5 次都行,当 2 个就够的时候,就不再往下匹配
- 独占模式 (js 不反对)
如果在表达式后加上一个加号(+),则会开启独占模式。同贪心模式一样,独占模式一样会匹配最长。不过在独占模式下,正则表达式尽可能长地去匹配字符串,一旦匹配不胜利就会完结匹配而不会回溯。
正则的性能
正则引擎次要的两大类:一种是 DFA(确定型有穷自动机),另一种是 NFA(不确定型有穷自动机)。NFA 对应正则表达式主导的匹配,DFA 对应文本主导的匹配。
DFA 从匹配文本动手,从左到右,每个字符不会匹配两次,它的工夫复杂度是多项式的,所以通常状况下,它的速度更快,但反对的个性很少,不反对捕捉组、各种援用等等;
NFA 则是从正则表达式动手,一直读入字符,尝试是否匹配以后正则,不匹配则吐出字符从新尝试,通常它的速度比较慢,最优工夫复杂度为多项式,最差状况为指数级。
NFA 反对更多的个性,因此绝大多数编程场景下(包含 java,js),咱们面对的是 NFA。
吐出字符从新尝试就是 回溯。
正则表达式回溯法原理