正则表达式
. 匹配任意字符
正则表示的是一个组合,配合任意一个非断行字符
.转义
\w 表示文字和大小写字母_
\W 表示\w的反向匹配字符
\d 表示匹配阿拉伯数字
\D 匹配非数字
\s 空格,tab,换行
\S 非
[] 匹配[]中的任意一个值,也可以是范围,如果想匹配中文,可以使用中文的unicode
\u4e00-\u9fa5,\u表示是万国码unicode,4e00和9fa5表示中文文字之间的范围,给定的是一个unicode范围,[ab]a或者b
+表示前面的字符可以出现一次或者多次
[ab][cd]+表示方括号的唯一值可以出现一次或多次,a或者b表示唯一的值
.在括号中要转义
- 表示0次或者多次
?表示0次或者1次
{} 表示匹配字符的重新字数
分组匹配
使用()进行分组 2 表示第二组
贪婪,尽可能的多
a.b aabaaab => aabaaab 默认是贪婪模式,.会尽可能多的去匹配组,尽可能多的去匹配。
a.?b aabaaaab => aab 尽可能少的去匹配,尽可能少的去匹配
在匹配次数后面加问号,表示懒惰 *?重复任意次,尽可能少的重复。+?重复一次或更多次,尽可能少的重复。??重复0或者1次,但尽可能少的重复。
位置符
^ $ ?=x \b \B
12332132 => 12.332.132
首先我们需要在两个位置中插入两个点,所以需要找出这两个位置,位置都出现在了三个数字的前面,并且还需要从后往前匹配,所以需要匹配行尾部
/(?=\d{3})+之间的位置,位置和元素之间也可以匹配位置。
(?=p) 其中p是一个子模式,即p前面的位置
(?!p) 不是p前面的位置
位置的特性
对于位置的理解,我们可以理解成空字符
- 不匹配任何东西的字符
/.^/ 开头的位置前面是没有字符的
-
弄出最后一个分号12131232
(?=\d{3}则表示正则的最后三位
弄出所有的逗号
(?=(\d{3})+)
(?!\b)(?=(\d{3})\b)
格式化
把字符串1888 => ');
}
验证密码的问题
是否包含某种字符
判断是否包含数字,将字符串中的所有位置找出来(?=.\d)判断这个位置的后一个字符是否是数字,如果存在这样的匹配,那么说明字符串中有数字
位置匹配的字符串往往放在字符串的最前面
(?=.\d)(?=.[a-z])
(?=.[0-9])^,表示开头前面还有个位置 -
正则表达式括号的作用
括号提供了分组,便于我们引用它。
引用包括两种情形,一种在js里引用,另一种在正则里引用
分组与分支结构
-
分组
比如(ab)+()括号提供分组,使得+量词作用于()内部的整体,即提供子表达式。
|分支往往要搭配分组括号使用 -
分组引用
正则引擎在匹配的过程中,会给每一个分组开辟一个空间,用来存储每个分组的数据。
match返回一个数组,第一个元素是整体匹配结果,然后是各个分组匹配的内容,然后是匹配下标,是否有修饰符g,match返回的结果也不一样
同时也可以通过正则构造函数的全局属性来获取分组
只要执行正则操作即可,比如test,exec,match
RegExp.2
let regex = /(\d{4})-(\d{2})-(\d{2})/
let string = '2019-08-09'
string.replace(regex, '$1/$2/$3')
==
string.replace(regex, () => RegExp.$1 + '/' + RegExp.$2 + '/' + RegExp.$3)
string.replace(regex, (match, year, month, day) => )
正则被执行后会保存分组,分组通过全局的正则函数RegExp访问,
replace的第二个参数可以是回调函数,回调函数的第一个参数是正则匹配到的值,后面的参数是分组
- 反向引用
除了使用相应的api引用分组,也可以在正则本身里引用分组。但是只能引用之前出现的分组。既反向引用。
/\d{4}(-|/|.)\d{2}(-|/|.)\d{2}/
/\d{4}(-|/|.)\d{2}\1\d{2}/
\1 \2 在正则里分别代表第一个和第二个分组
分组会将匹配到的内容提取出来,保存到内存中
1.如果引用了不存在的分组,就会反向匹配引用字符本身
- 如果分组后面有量词,那么最终捕获到的数据是最后一次的匹配
之前文中出现的括号,都会捕获他们匹配到的数据,以便后续引用,因此也称捕获行分组,如果只是使用括号里最原始的功能,(?:xxx)
字符串trim方法模拟
/^\s|\s$/g 去掉首尾空格
将每个单词的首字母转换为大写
string.replace(/(\s|^)\w/g, (value) => value.toUpperCase())
驼峰转换
string.replace(/-(\w)/g, (value, group1) => group1.toupperCase())
html转义
const escapeHTML = (str) => {
const escapeChars = {
'<': 'a'
}
return str.replace(new RegExp('[' + Object.keys(escapeChars).join('') + ']')
(value) => escapeChars[value]
)
}
/<([a-z]+)>.+</\1>/g
正则表达式的回溯法原理
内容:
- 没有回溯的匹配
- 有回溯的匹配
- 常见的回溯形式
回溯法也称试探法,从问题的某一种状态出发,探索从这种状态出发所能达到的所有状态,当一条路走到尽头的时候,再后退一步或者若干步,从另一种可能的状态出发,继续搜索,直到所有的可能都被探索过。这种不断前进不断回溯的方法就叫回溯法。本质上就是深度优先搜索算法,其中退到之前某一步的过程,我们称为回溯
-
贪婪量词
比如b{1, 3}因为其是贪婪的,尝试可能的顺序是从多往少的方向去尝试,首先尝试bbb,然后看整个正则能否匹配,不能匹配时,吐出一个b,再继续尝试,往复循环,直到满足要求。 -
惰性量词
惰性量词就是在贪婪量词后面加一个? -
分支结构
分支结构也是惰性的,比如/can|candy/,得到的结果是can,因为分支会一个一个尝试,如果满足了就不会在尝试后面的分支。
非捕获分组?
当尝试匹配时,需要确定从哪一个位置开始匹配,一般都是从字符串的开头
当使用test和exec方法,且正则有g时,起始位置是从正则实例的lastIndex位置开始。
优化正则性能
- 通过使用非捕获型分组提升性能
- 独立出确定字符
- 提取分支公共部分
- 减少分支的数量,缩小它们的范围
正则表达式的四种操作
- 验证
match返回结果的格式问题,分为是否有g两种情况
没有g => [ 匹配的值,分组匹配的值,匹配开始的位置,需要匹配的字符串 ]
有g => 返回的是所有匹配的内容
当没有匹配时,不管有无g,都返回null