4

正则表达式

重新整理学习,为了加深印象,发现了之前遗漏的一个非常重要的知识点优先选择最左端的匹配结果,这个规则

js上创建正则的方式

  • 直接字面量的创建

    const r = /xx/;    //通过双斜杠,在中间添加匹配的规则,这样就是一个正则表达式了
  • 通过构造函数创建

    const r = new RegExp('xx', g)  //通过构造函数来创建正则对象,第一个参数为匹配规则字符串,第二个参数可以添加修饰符,例如g,i,m,y

正则的实例方法

  • 常用的exec,可以返回一个类数组,信息比较全

    const r = /a/g
    r.exec('asd')   //返回["a", index: 0, input: "asd", groups: undefined]0: "a"groups: undefinedindex: 0input: "asd"length: 1__proto__: Array(0)

    可以看看返回的信息有些什么?

    • 一个元素代表:整体匹配返回的结果,如果正则中有子组匹配,那么会在index元素前返回,例如

      /(a)s/g.exec('afasg')  // 返回 ["as", "a", index: 2, input: "afasg", groups: undefined]
    • index就是匹配的索引位置信息
    • input就是目标字符串是什么,
    • groups这边返回undefined,因为正则中没用到;它是返回自定义名字的子匹配信息,例如

      /(?<groupone>a)s/g.exec('afasg')
      //返回  ["as", "a", index: 2, input: "afasg", groups: {groupone: "a"}]
  • 不常用的方法test,返回Boolean值,表示是否有匹配的字符串

正则的重要规则

比较全的规则,在这

我讲讲几个比较重要的,常用的

  • 修饰符:i,m,g,y,修饰符之间可以同时使用
    i就是忽略大小写,例如验证码上的应用 => /a/i.test('A') //true
    m就是能识别换行,也就是能判断出行末

    /a$/.test('a\nb')  //false 
    /a$/m.test('a\nb')  //true

    g是能进行连续的匹配,当匹配成功一次后还能继续匹配直到没有为止,并且可以通过lastIndex可以查看下一次匹配的开始的索引但是只对同一个正则有效,能连续指定,不然都是从零开始,这里的同一个是指内存地址相等,不是内容相等就够了

    const r = /a/g      //这里通过变量r定义这样用r进行后面的操作都会是用一个
    r.lastIndex         //0
    r.test('asdasd')    //true
    r.lastIndex         //1

    y一般和g连用,y的作用是必须从一开始就匹配上,不然就false;相当于加了个^

    /a/y.test('ba')  //false
    /a/y.test('ab')  //true ,一般和g连用,进行连续头部匹配是否成功
  • \b,\B用于匹配是否是词的边界,不存在/wbw/它的意思就是是否存在一个是词的边,但前面又有一个w,明显是不存在的(w等价于[A-Za-z0-9_])

    /\ba/g.test('ad') //true 
    /\ba/g.test('bad') //false
    /\ba/g.test('c-ad') //true  
    \B就是取反不是词的边界
  • [],()之间的区别,这两个分成常用
    []仅仅代表一个字符串,不管里面写多少规划,最终还是会去匹配一个字符串
    常用的有

    [xyz]   //代表匹配x或者y或者z
    [^]     //等价于[^''],任意字符串
    [\S\s]  //任意字符串   ,\s是匹配空格,换行(一些带有空格的u码,详细可以看链接) \S就是匹配除了\s意外的字符串

    ()是用于取子匹配的值,又叫元组;有时候我们整体匹配上了,但又想在里面取某个值就可以加上个括号,结果中就会帮你返回,在将exec时以及提到了,这边不举例了
    可以和字符串的replace方法一起使用,进行负复杂的操作

    const r = /he(b)/g
    'afdhjbkhbgd'.replace(r, (match, $1) => {
        //match 是整体匹配的结果,$1是第一个元组返回值,当多个元组存在时是有外到里的
        return xxxx
    })
  • .代表一个字符,除了空格,类似换行;还有一些大于大于0xFFFF的字符,他会认为这是两个字符,所以用于简单的任意字符串匹配,可用.代表
  • 量词
    a{n}可以用来代表去匹配n个a,还可以写区间{1,3}匹配1到3个
    +,*,?这些事贪婪匹配的量词,就是数量往大了取,不固定,但又范围+ //[1, Infinity] * //[0, Infinity] ? //[0, 1]

    如果在其后面再添加个?就是非贪婪匹配了,取值就尽量往小了取
    非贪婪匹配的作用在哪,可以通过一个简单的例子看一下

    //如果要匹配字符换'caabaaab' ,如果只想取aab就会用到非贪婪匹配 通过/a+?b/g来匹配;用?来指定非贪婪匹配,加上b的限制,不会取到1;这边用+还是*是一样的
  • 强大的断言
    可以理解成你是用于匹配的规则但不是我想要输出的内容

    • 非捕获组
      ?:表示;说直白点就是:还是这么匹配但是我不返回括号里的内容,所以我们进行split的组匹配时可以进行修改console.log("abc".split(/(?:b)/)); //["a", "c"]
    • 先行断言
      x(?=y)表示,意思是匹配一个x,x必须在y前面,结果中不返回y
    • 先行否定断言
      x(?!y)表示,意思是匹配一个x,x后面不能是y,结果中不返回y
    • 后行断言
      (?<=y)x表示,意思是匹配一个x,x前面必须是y,结果中不返回y
    • 后行否定断言
      (?<!=y)x表示,意思是匹配一个x,x前面不能是y,结果中不返回y

      console.log(/(?<!=b)a/.exec("bcaba"));  //["a", index: 2, input: "bcaba", groups: undefined]
      console.log(/(?<=b)a/.exec("bcaba"));   //["a", index: 4, input: "bcaba", groups: undefined]

最重要最优先的规则

  • 优先选择最左端的匹配结果
    可以通过几个例子自证一下

    /a+?b/.exec('baaabab')    
    //结果["aaab", index: 1, input: "baaabab", groups: undefined],因为先匹配上了aaab,所以忽略非贪婪原则不输出ab或者b
    
    /a*?/.exec('baaa')
    //返回["", index: 0, input: "baaa", groups: undefined]  因为先匹配上了空串所以结果为空串

常见的正则例子

  • 去除首尾空格 ' fds df '.replace(/^\s*|\s*$/g, '')
  • 去除首尾空格 ' fds df '.replace(/\s*(?=\S*)/g, '')
  • 千分位数字格式化 '1234567890'.replace(/\B(?=((\d{3})+$))/g, '.');
    如果有小数, ('1234567890.123').replace(/\B(?=((\d{3})+\.))/g, ',')
    合并两者: ('1234567890.213').replace(/\B(?=((\d{3})+(\.\d+)?$))/g, ',')

`


Infinity
293 声望9 粉丝

学前端中,只想激情优雅的写代码