JS 正则表达式总结

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.位置和序列 ^ 、$、 \元字符、 一般字符

    1. 管道符(竖杠)|.

    上面操作符的优先级从上至下,由高到低。

2、写好正则的建议

  • 使用具体型字符组来代替通配符,来消除回溯
    少用通配符'.',减少回溯次数,提升匹配速度
  • 使用非捕获型分组(?:)
    当必须要用括号,又不想引用时,使用非捕获型分组可节省内存
  • 独立出确定字符
    例如/a+/,可以修改成/aa*/。后者能比前者多确定了字符a,可加快判断是否匹配失败,进而加快移位的速度
  • 提取分支公共部分
    比如/abc|def/,修改成/^(?:abc|def)/。这样做,可以减少匹配过程中可消除的重复。
  • 减少分支的数量,缩小它们的范围
    /red|read/,可以修改成/rea?d/。此时分支和量词产生的回溯的成本是不一样的。

3、正则相关JS函数

String类型四个+RegExp类型二个,常用的是3+1

  • match
    当全局匹配时,match返回所有匹配结果,数组形式;
    当局部匹配时,match返回一个结果和其它信息,如index,input,数组形式;
    当没有匹配到数据时,返回null

    var 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})+$) 表示从结尾的位置开始往前连续三个数字之前的位置

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容