0、前言
作为一名前端开发者,在做表单验证或者写一些gulp任务或webpack配置时都不可避免的会用到正则,虽然零零散散看过一些正则相关语法,但始终觉得没吃透,直到遇到这篇文章(强烈推荐)。本文仅记录个人觉得很有价值的几个点。
1、正则语法
正则是匹配模式,要么匹配字符,要么匹配位置。
对于一个字符串string='hello',你应该这样看待它:
也就是要看成字符和位置的集合,而不是单单的是字符。
字符组
范围表示法:[a-z]从a到z的所有小写字母;
排除字符组:[^a-z]除a-z以外的所有字符;
常见缩写:\d,\D,\w,\W,\s,\S,.,其中'.'匹配任意非换行符、回车符、行分隔符和段分隔符。
此外,若要匹配任意字符,可用:[\d\D]、[\w\W]、[\s\S]和[^]中任何的一个。-
多选分支
(p1|p2|p3),其中p1、p2和p3是子模式,用|(管道符)分隔,表示其中任何之一
注意:分支结构是惰性的,当第一个子模式匹配成功后,后面的模式会被忽略
-
位置匹配符(6个)
^ $ \b \B (?=p) (?!p)
^:开始的位置;
$:结束的位置;
\b:单词边界,具体就是\w和\W之间的位置,也包括\w和^之间的位置,也包括\w和$之间的位置;
\B:\b的取反;
(?=p):p之前的位置,正向先行断言;
(?!p):上述取反,反向先行断言;
把位置理解空字符,是对位置非常有效的理解方式。同一个位置可以有多个空字符,就像^和首字母之间还可以有其它空位置一样 -
括号的作用
1、分组和分支/(ab)+/ //分组 /^I love (JavaScript|Regular Expression)$/ //分支
2、分组引用
主要是方便获取小括号匹配到的内容//1、match方法,有小括号时,返回的数组中包含小括号匹配的内容 var regex = /(\d{4})-(\d{2})-(\d{2})/; var string = "2017-06-12"; console.log( string.match(regex) ); // => ["2017-06-12", "2017", "06", "12", index: 0, input: "2017-06-12"] //2、API引用法,使用replace时可直接用$1等获取小括号内容 var regex = /(\d{4})-(\d{2})-(\d{2})/; var string = "2017-06-12"; regex.test(string); // 正则操作即可,例如 //regex.exec(string); //string.match(regex); console.log(RegExp.$1); // "2017" console.log(RegExp.$2); // "06" console.log(RegExp.$3); // "12" //3、反向引用 \1,\2 var regex = /\d{4}(-|\/|\.)\d{2}\1\d{2}/; var string1 = "2017-06-12"; var string2 = "2017/06/12"; var string3 = "2017.06.12"; var string4 = "2016-06/12"; console.log( regex.test(string1) ); // true console.log( regex.test(string2) ); // true console.log( regex.test(string3) ); // true console.log( regex.test(string4) ); // false
3、非捕获分组
非捕获分组的意义在于不引用括号的内容,节省内存var regex = /(?:ab)+/g; var string = "ababa abbb ababab"; console.log( string.match(regex) ); //=>RegExp.$1值为'''',不用非捕获模式时为"ab"
-
符号的优先级
一个正则表达式涉及的操作符有:1.转义符 \
2.括号和方括号 (...)、(?:...)、(?=...)、(?!...)、[...]
3.量词限定符 {m}、{m,n}、{m,}、?、*、+
4.位置和序列 ^ 、$、 \元字符、 一般字符- 管道符(竖杠)|.
上面操作符的优先级从上至下,由高到低。
2、写好正则的建议
- 使用具体型字符组来代替通配符,来消除回溯
少用通配符'.',减少回溯次数,提升匹配速度 - 使用非捕获型分组(?:)
当必须要用括号,又不想引用时,使用非捕获型分组可节省内存 - 独立出确定字符
例如/a+/,可以修改成/aa*/。后者能比前者多确定了字符a,可加快判断是否匹配失败,进而加快移位的速度 - 提取分支公共部分
比如/abc|def/,修改成/^(?:abc|def)/。这样做,可以减少匹配过程中可消除的重复。 - 减少分支的数量,缩小它们的范围
/red|read/,可以修改成/rea?d/。此时分支和量词产生的回溯的成本是不一样的。
3、正则相关JS函数
String类型四个+RegExp类型二个,常用的是3+1
-
match
当全局匹配时,match返回所有匹配结果,数组形式;
当局部匹配时,match返回一个结果和其它信息,如index,input,数组形式;
当没有匹配到数据时,返回nullvar string = "2017.06.27"; var regex1 = /\b(\d+)\b/; var regex2 = /\b(\d+)\b/g; console.log( string.match(regex1) ); console.log( string.match(regex2) ); // => ["2017", "2017", index: 0, input: "2017.06.27"] // => ["2017", "06", "27"]
split
1、接受第二个参数,表示分割后数组的长度;
2、和match一样,当第一个参数是字符串时会将其转为正则表达式,因此建议不要传字符串,而是直接传正则replace
1、第二个参数可以是字符串或者函数,当是函数时,第一个参数表示整个匹配的内容,然后依次是括号匹配的内容,再然后是index和input;
2、str.replace返回的是新字符串,str本身并未被改变,即replace是不改变原始字符串的。-
test
/\d+/.test(123);//true
4、总结
- 操作符优先级:转义>括号>量词>普通字符>管道符
- 正则表达式不光匹配字符,还匹配位置
- 位置符:^ $ (?=b) (?!b) \b \B,其中\b是\w与\W之间的位置,(?=b)是b之前的位置
- ^与首字母之间还可以有位置,尾字母和$同理。即同一个位置可以有多个空白字符。
- 写好正则的建议 -第二节
5、案例
- 把"12345678",变成"12,345,678"
var string1 = "12345678",
string2 = "123456789";
reg = /(?!^)(?=(\d{3})+$)/g;
var result = string1.replace(reg, ',')
console.log(result);
// => "12,345,678"
result = string2.replace(reg, ',');
console.log(result);
// => "123,456,789"
(?!^) 表示非开头的位置
(?=(\d{3})+$) 表示从结尾的位置开始往前连续三个数字之前的位置