likes
comments
collection
share

JavaScript 深入正则表达式

作者站长头像
站长
· 阅读数 37

正则表达式是一个专门用来检测 字符串 是否符合规则的表达式,大部分语言都能有用到,作为前端程序员,在一般业务中使用的都不多,但至少要了解其基本特性,常用的表达式就不在这里列举了,百度一搜一大把的~

创建方法
    1. 字面量方式创建

      • 语法: var reg = /abcd/ 意义:检测的字符串内必须包含一个 'abcd' 字符串片段
    2. 内置构造函数方式创建

      • 语法: var reg = new RegExp('abcd')

        可以省略new 括号里可传两个参数('abcd', 'gi') i或g写在后面

  • 两种表达式的区别

    • 字面量方式不接受字符串拼接

      内置构造函数: 可以拼接字符串, 因为第一个参数就是以字符串的形式书写正则内容

    什么是拼接字符串?

    var a = [ 'HH', 'NN', 'MM' ]
    a.join('|')  =>  HH|MM|NN
    var reg2 = new RegExp('(' + a.join('|') + ')')
     console.log(reg2)
    
    • 书写基本元字符
      • 字面量方式 直接书写 \s\d\w
      • 内置构造函数 需要书写 \\s\\d\\w
    字符串
    + 有一个特殊符号叫做 转义符号(\)
    + 可以吧有意义的转化成没有意义的文本, 把没有意义的文本转换成有意义的符号
    => 例子: \n
    => n 本身是没有意义的文本
    => \n 表示换行的意思
    + 当你在字符串内书写 \s
    => 会把没有意义的 s 文本转换成有意义的符号
    => 但是字符串内没有 \s 这个符号
    => 其实就是还是 s 文本
    正则
    + 第一个参数一字符串的形式书写正则内的内容
    + 你书写的是 '\s\d\w', 因为在字符串内确实没有 \s\d\w 这三个符号, 所以其实就是 sdw 文本
    + 当你书写 '\\s' 的时候
    => 第一个 \ 是转义符号, 把第二个 \ 给转换了
    => 转换成了一个没有意义的 \ 文本
    + 你给出的 '\\s\\d\\w' 其实才是一段合法的元字符文本
    
常用方法
    1. 匹配方法

      • 语法: 正则.test(字符串)
      • 返回值: 布尔值, 有就是true 没有就是false
    • 用一个正则表达式不要连用 test
      let reg = /a/g // 不加g 没影响
    console.log(reg.test('fasdg')) // true
    console.log(reg.test('fsasdg')) // 当a在前两位的时候是 false 第三位开始才是 ture
    
  1. 捕获方法

    从一段完整字符串中获取出一部分满足正则表达式的内容片段

    • 语法: 正则.exec(字符串)

    • 返回值:

      如果原始字符串中没有符合的片段,就是null

      如果原始字符串中有符合的片段,那么就是一个数组

      2-1 没有() 也没有全局标识g

      ​ [0] 就是捕获出来的第一个片段,有且仅有第一个满足规则的片段

      2-2 有全局标识g

      ​ [0] 就是捕获出来的第一个片段

      ​ 第二次捕获的时候会从第一次捕获结束的位置开始检索

      ​ 每一次捕获返回的[0]都是新的片段,直到捕获不到内容为止,返回null后再下一次捕获又从字符串开始位置检索

      2-3 有()

      ​ 在返回值数组中,从[1]开始,依次是每一个()的单独内容

      • 匹配但不捕获

        • 语法: (?:) 写在冒号后面

          这种就是需要用到括号,但是还不想捕获括号里面的内容的时候要用

          比如(?:\d|x) 这种需要或的情况的时候

标识符

用来修饰整个正则表达式的

  • 标识符位置

    • 字面量方式: var reg = /abcd/(写在这里,顺序任意)
    • 内置构造函数方式: var reg = new RegExp('abcd', 'gi') 第二个参数
  • 标识符种类

    1. i 忽略大小写
    2. g 全局匹配,多用于重复执行
    3. m 换行匹配 => 如果匹配字符串遇到换行,那么重新开始计算行首

    例如/^\d/gm 替换的话如果有多行,是替换每一行的第一个数字

元字符

填写在正则表达式内的规则符号

  • 基本元字符

    1. \d 表示 一位 数字
    2. \D 表示 一位 非数字
    3. \s 表示 一位 空白内容(空格,缩进,换行...)
    4. \S 表示 一位 非空白内容
    5. \w 表示 一位 数字(0-9)字母(a-zA-Z)下划线(_)都行
    6. \W 表示 一位 非数字字母下划线
    7. . 表示 一位 非换行以外的任意内容
    8. \ 转义符,把有意义的符号转化成没有意义的文本,把没有意义的文本转换成有意义的符号
  • 重复元字符

    \n 表示重复出现第n个小括号的内容,必须和之前出现的一样

    \1 表示在 \1 位置重复出现一次第一个小阔内的内容内容而且必须和 第一个小括号出现的内容一模一样

    \1* 表示重复第一个括号里面的内容至少重复1次 \1+ 表示至少重复两个 使用\1 这种的方法 前面的东西必须放在群组里 ([a-z])\1*

  • 边界符
      1. ^ 表示字符串开头
      2. $ 表示字符串结尾

      注意: 当 开头和结尾 一起使用的时候, 表示从开头到结尾

      var emailX = /^[^_]\w{4,11}@(qq|163|sina)\.(com|cn)$/
      =>邮箱验证,开头到结尾有5-12个\w组成
      
  • 限定符

    用来修饰出现多少次的符号 注意: 一个限定符只能修饰前面一个符号

    1. * 表示0~多次(包含0)

    2. + 表示1~多次

    3. ? 表示0~1次(没有或只有1次)

    4. {n} 表示n次

      => {0,} 等价于 * , {1,} 等价于 +

      注意点:想要使用这个,正则表达式中必须含义结尾,否则大于n的次数也是可以测试通过的,只不过捕获的时候还是捕获n个

      {0} 匹配空字符,不论前面有什么,都匹配的是空, 如'abc' 匹配到 4个空字符串

    5. {n,m} 表示n~m次

      => {0,1} 等价于 ?

  • 特殊符号

    1. ( ) 组

      含义1: 表示一个整体

      含义2: 表示单独捕获

    2. | | |中间如果没写,查的是空字符, 两侧任意一边没有写,查的是空字符

      表示左边或者右边的任意一个都行

      let reg = /^18|29$/ 匹配的是:以18开头或者以29结尾的都可以
      let reg = /^(18|29)$/ 匹配的是:18或者29中的一个 只能出现一次
      
    3. [ ]

      表示 [] 内的任意一个都行 , 相同字符无意义 如[aba] 只匹配a或b

      . 在中括号内是字符点, 不再是通配符 中括号内再匹配 [] () {} 时需要 \ 转义

    4. [^]

      表示 [^] 内的任意一个都不行

      以上两个中括号都是只占一个字符位置,括号内可以写多个字符

    5. -

      表示从一个字符到一个字符, 必须要 ASCII 编码连着的 和 [] 或者 [^] 连用

      • [0-9] 等价于 \d [0-9a-zA-Z_] 等价于 \w [ ^0-9] 等价于 \D [^0-9a-zA-Z_] 等价于 \W
断言和重复筛选
  • 重复筛选

    • ( )\1+ ( )\1* 表示括号里面的内容需要重复最大的次数 贪婪匹配 1+ 至少有两次 1* 至少有一次
    let str = 'asdfsdfsadfsafdsagwhhtrhgdvg'
    function strTimes(str){
        return str.split('').sort().join('').replace(/(a-zA-Z)\1*/g,function(item){
            return item[0] + '{' + item.length + '}'
    	})
    }
    
  • 断言

    断言语句不占位,且不会出现在返回值当中, 只是判定前后是否存在

    1. 后置肯定断言
      • 语法: ?= 表示前面的内容后面必须包含后面这个内容 存在则匹配前面的内容
    2. 后置否定断言 语法: ?!
    3. 前置肯定断言 语法: ?<= 判定后面的内容前面是否存在这个内容 存在则匹配后面的内容
    4. 前置否定断言 语法: ?<!
    console.log("《西游记》,《三国演义》,《水浒》,《红楼梦》".match(/(?<=《).*?(?=》)/g)) 返回不包含《 》组成的数组
    
两大特性
    1. 懒惰

      每当使用正则去捕获字符串的时候,每次都是从开始位置检索,一般只返回一个值

      • 解决: 使用全局标识符g
    2. 贪婪

      在使用了区间写法的时候,在捕获的时候会尽可能多的去捕获内容,也就是捕获满足条件的最长组合,这种就是默认的贪婪匹配

      • 解决: 非贪婪匹配(捕获满足条件最小长度) 在限定符后面加上?

        .*? .+? 这两个前后都必须有条件 如 a.*?b 有起始和结束

        ?? ===== {0,2}

        {n,}? {n,m}?

和字符串的组合方法
  1. replace()
    • 语法: 字符串.replace(正则表达式,换上字符),字符串.replace(正则表达式,函数)
    • 这里的函数(参数1,参数2,...,参数3,参数4) 参数1 是每次找到的内容,参数二是使用()后筛选后的内容,倒数第二个参数是下标,最后一个参数是原字符串, 函数可以简写'1∗∗∗∗1****12'$1 就是群组1 表示原本第几个() 里面的内容是啥 返回的就是啥
    • 返回值: 不填写全局g替换一个,填写g有多少替换多少

用此方法替换关键字:

var str = 'fXXfdHHsMMgNNfHHdNNhHHgfsMMdsNNgsdb'
var a = [ 'HH', 'NN', 'MM', 'XX' ]
var r3 = str.replace(new RegExp('(' + a.join('|') + ')', 'g'), '**')
console.log(r3)
var str="2[2[2[ab]2[cd]]3[c]]"  // 拆开成对应次数
function pares(str){
if(!/(\d+)\[(a-zA-Z)+\]/g.test(str)) return str
str = str.replace(/(\d+)\[(a-zA-Z)+\]/g , function(item,$1,$2){
return $2.repeat($1)
})
return pares(str)
}
  1. search()

    • 语法: 字符串.search(正则表达式)

    • 返回值: 有满足条件的片段,就是索引位置

没有满足条件的片段,就是-1

  1. match()

    • 语法: 字符串.match(正则表达式)

    • 返回值: 没有全局g,和exec方法一样

有全局标识g,返回一个数组,捕获全部满足条件的片段组成的数组

// match 使用组匹配
console.log("1234567890".match(/^(\d{3})(\d{4})(\d{3})$/).slice(1)) 

  1. split()

    • 语法: 字符串.split(正则表达式)

    • 返回值: 分割剩下的子串组成的数组

    这里正则可以不用写g,因为split方法自己会匹配全局,这个和字符串本身方法的区别是可以写或

转载自:https://juejin.cn/post/7179423825472258105
评论
请登录