美文网首页
正则相关

正则相关

作者: 行走的蛋白质 | 来源:发表于2020-03-06 22:50 被阅读0次

    regular expression


    • 千分位
    str.replace(/(\d)(?=(\d{3})+(\.)?)/g, '$2,');
    

    正则表达式的创建

    • 字面量模式 let reg = /\d+/; 缺点是无法拼接变量
    • 构造函数模式 let reg = new RegExp('\d+'); 可以拼接变量,可以有第二个参数值为修饰符
    // 全局匹配数字为例,下述两个等同
    let reg01 = /\d+/g
    reg01 = new RegExp('\\d+', 'g')
    

    元字符和修饰符两部分组成

    元字符
    • 量词元字符:设置出现的次数
    符号 含义
    * 零到多次
    + 一到多次
    ? 零次或一次
    { n } 出现 n 次
    { n, } 出现 n 到多次也就是至少 n 次
    { n, m } 出现 n 到 m 次
    • 特殊元字符:单个或者组合在一起代表特殊的含义
    符号 含义
    \ 转义字符
    \n 换行符
    . 非 \n
    ^ 以哪一个字符作为开始
    $ 以哪一个字符作为结束
    \d 0~9之间的一个数字
    \D 非 \d
    \w 数字、字母、_ 下划线中的任意一个字符
    \W 非 \w
    \s 一个空白字符 - 空格、制表、换页符等
    \t 制表符 - TAB 键 - 四个空格
    \b 匹配一个单词的边界
    x|y x 或者 y 中的一个字符
    [xyz] x 或者 y 或者 z 中的一个字符
    [^xy] 除了 x y 中的任意一个字符
    [a-z] a 到 z 这个范围中的任意一个字符比如 [a-z0-9A-Z_] === \w
    [^a-z] 非 [a-z]
    () 正则中的分组符号
    (?:) 只匹配不捕获
    (?=) 正向预查
    (?!) 反向预查
    • 普通元字符:代表的就是本身含义
      /protein/: 此正则匹配的就是 "protein"
    修饰符
    符号 含义
    i ignoreCase 忽略单词大小写匹配
    m multiline 可以进行多行匹配
    g global 全局匹配

    易混淆的中括号 [] () ?

    [] 的用法
    • 里面出现的字符一般都代表其本身的含义 \d 是个例外它还代表数字
    // 比如 /^[@+]$/ 代表 @ 或者 + 其中一个
    // /^[@+]+\$/ 代表 @ 或者 + 其中一个出现一次或者多次(每次都是独立事件)
    let reg03 = /^[@+]$/
    console.log(reg03.test('@+')) // false
    
    reg03 = /^[@+]+$/
    console.log(reg03.test('@+')) // true
    
    • 中括号中不存在多位数
    // 比如 /^[18]$/ 代表 1 或者 8
    //  /^[(18)]$/ 代表 ( 或者 ) 或者 1 或者 8
    // /^[(12-78)]$/ 代表 ( 或者 ) 或者 2 到 7 之前的数字或者 1 或者 8
    let reg04 = /^[18]$/
    console.log(reg04.test('1')) // true
    console.log(reg04.test('8')) // true
    console.log(reg04.test('18')) // false
    
    reg04 =  /^[12-78]$/
    console.log(reg04.test('1')) // true
    console.log(reg04.test('6')) // true
    console.log(reg04.test('8')) // true
    console.log(reg04.test('18')) // false
    
    () 的含义
    • 提升优先级
    • 分组捕获
    • 分组引用,就是通过数 "\数字" 让其代表和对应分组出现一模一样的内容
    let str2 = 'book' // 'look' 'hook'这种重复的元素
    let reg = /^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/
    console.log(reg.exec(str2))
    
    ? 的含义
    • 左边是非量词元字符,代表零次或一次
    • 左边是量词元字符,代表取消贪婪性
    • (?:) 只匹配不捕获
    • (?=) 正向预查
    • (?!) 反向预查

    常用正则实例

    有些具体还是要根据实际业务变通

    1. 验证是否为有效数字
    /** 
    * 1. 可能出现 +- 也可能不出现 --- [+-] 或者 (+|-)?
    * 2. 一位数位 0-9 都可以,多位数首位不为 0 --- (\d|([1-9]\d+))
    * 3. 小数位可能有可能没有,如果有小数点后面必须有数字 --- (\.\d+)?
    */
    // let reg06 = /^[+-]?(\d|[1-9]+)(\.\d+)?$/  // 忽略了多位数从第二位开始可能会有 0 的情况
    let reg06 = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/
    
    2. 验证密码
    /**
    * 数字、字母、下划线
    * 6 ~ 16 位
    */
    let reg07 = /^\w{6,16}$/
    
    3. 验证真实姓名
    /**
    * 1. 汉字 /^[\u4E00-\u9FA5]$/
    * 2. 长度 2 ~ 10 位
    * 3. 可能有译名 ·汉字
    */
    let reg08 = /^[\u4E00-\u9FA5]{2,10}(·[\u4e00-\u9FA5]{2,10}){0,2}$/;
    
    4. 验证邮箱
    /**
    * 1. 开头是数字、字母、下划线,一到多位 --- \w+
    * 2. 接下来 -数字、字母、下划线或者 .数字、字母、下划线,它们的整体 0 到多位 --- ((-\w+)|(\.\w+))*
    * 1. 2. => 邮箱的名字由 数字、字母、下划线开始和结束,中间可以有不连续的 - 或者 . 出现
    * 中间 为 @ 符号
    * 3. @ 后面紧跟数字、字母,一到多位 --- [a-zA-Z0-9]+
    * 4. 最后匹配域名 一个 . 后面跟一到多个数字或者字母 --- \.[a-zA-Z0-9]+
    * 5. 在 4 之前匹配 . 或者 - 后面跟一到多个数字或者字母,它们整体出现 0 到多次 --- ((\.|-)[a-zA-Z0-9]+)*
    */
    let reg09 = /^\w+((-\w+)|(\.\w+))*@[a-zA-Z0-9]+((\.|-)[a-zA-Z0-9]+)*\.[a-zA-Z0-9]+$/
    
    5. 身份证号码
    /**
     * 1. 一共 18 位
     * 2. 最后一位可能是 X
     * => /^\d{17}[0-9X]$/ /^\d{17}(\d|X)$/
     * 3. 规则 - 前六位代表省市县
     * 4. 规则 - 中间八位为出生年月日
     * 5. 规则 - 最后一位是 X 或者数字
     * 6. 规则 - 倒数第二位偶数是女,基数是男
     * 7. 规则 - 其余两位根据上述数字计算得出
     * => 小括号第二个作用:分组捕获,即不仅匹配整体信息还可以单独捕获小分组的内容
     */
    let reg10 = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d{1})(\d|X)$/
    reg10.exec('130622199708092345') // ["130622199708092345", "130622", "1997", "08", "09", "4", "5", index: 0, input: "130622199708092345", groups: undefined]
    // 根据捕获数组可以查询对应省市县,可以知道出生年月日,可以知道性别
    // 如果不需要捕获可以用 ?: 只匹配不捕获来处理
    let reg10 = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d{1})(?:\d|X)$/
    reg10.exec('130622199708092345') // ["130622199708092345", "130622", "1997", "08", "09", "4", index: 0, input: "130622199708092345", groups: undefined]
    

    正则的捕获

    实现捕获的方法
    • RegExp.prototype 的方法 exec 和 test
    • String.prototype 的方法 replace\match\splite
    exec 方法
    • 结果是 null 或者一个数组
    let reg11 = /\d+/
    let str1 = 'jfla1989protein1997'
    let str2 = 'protein'
    
    console.log(reg11.exec(str1)) // [ '1989', index: 4, input: 'jfla1989protein1997', groups: undefined ]
    console.log(reg11.exec(str2)) // null
    
    • 懒惰性让它匹捕获到第一个符合条件的内容就会停止
      懒惰性的原因:正则有一个 lastIndex 属性,代表下一次匹配的起始位置。exec 之后这个值不会改变,每一次都是从字符串的开始位置 0 查找
    • 用全局修饰符 g 来改变 lastIndex 的值,从而打破懒惰性,如下实例形成一个闭环
    let reg12 = /\d+/g
    let str1 = 'jfla1989protein1997'
    
    console.log(reg12.lastIndex) // 0
    console.log(reg12.exec(str1)) // console.log(reg12.lastIndex)
    console.log(reg12.lastIndex) // 8
    console.log(reg12.exec(str1)) // [ '1997', index: 15, input: 'jfla1989protein1997', groups: undefined ]
    console.log(reg12.lastIndex) // 19
    console.log(reg12.exec(str1)) // null
    console.log(reg12.lastIndex) // 0
    console.log(reg12.exec(str1)) // console.log(reg12.lastIndex)
    console.log(reg12.lastIndex) // 8
    
    • 字符串的 match 方法可以捕获所有
    console.log(str1.match(reg12)) // [ '1989', '1997' ]
    
    test 方法

    RegExp.$1 ~ RegExp.$9 获取当前匹配的第一到第九个信息

    let str4 = '{2020}年{3}月{6}日'
    let reg4 = /\{(\d+)\}/g
    
    console.log(reg4.test(str4)) // true
    console.log(RegExp.$1) // 2020
    
    console.log(reg4.test(str4)) // true
    console.log(RegExp.$1) // 3
    
    console.log(reg4.test(str4)) // true
    console.log(RegExp.$1) // 6
    
    console.log(reg4.test(str4)) // false
    console.log(RegExp.$1) // 6
    
    console.log(reg4.test(str4)) // true 同样形成一个闭环
    console.log(RegExp.$1) // 2020
    
    replace 字符串中实现替换的方法一般伴随正则使用
    • 实例 1 '2020-03-06' === 2020年03月06日
    let str13 = '2020-03-06'
    let reg13 = /^(\d{4})-(\d{2})-(\d{2})$/
    let str131 = str13.replace(reg13, "$1年$2月$3日")
    console.log(str131) // 2020年03月06日
    

    实例 1 解析:

    1. replace 首先拿正则和字符串进行匹配,然后第二个参数接受一个回调函数,匹配几次就会执行几次
    2. 回调函数接收实参信息 - 为 exec 捕获到的数组里面的值对应实例 1 如下:
    let str132 = str13.replace(reg13, (initialstr, $1, $2, $3) => {
        console.log(initialstr, $1, $2, $3) // 2020-03-06 2020 03 06
    })
    
    1. 回调函数的返回值即为 replace 要替换的正则匹配到的内容
    let str133 = str13.replace(reg13, (initialstr, ...args) => {
        let [$1, $2, $3] = args
    
        $2.length < 2 ? $2 = '0' + $2 : $2
        $3.length < 2 ? $3 = '0' + $3 : $3
    
        return $1 + '年' + $2 + '月' + $3 + '日'
    })
    console.log(str133) // 2020年03月06日
    
    • 实例 2 单词首字母大写
    let str14 = 'good good study, day day up!'
    let reg14 = /\b([a-zA-Z])([a-zA-Z]*)\b/g
    
    let str141 = str14.replace(reg14, (initialstr, ...args) => {
        // 回调函数执行匹配的次数
        let [$1, $2] = args
        return $1.toUpperCase() + ($2 ? $2 : '')
    })
    console.log(str141) // Good Good Study, Day Day Up!
    
    正则捕获的贪婪性

    默认情况下,捕获的时候是按照当前正则所匹配的最长结果来获取

    let str3 = 'jfla1987protein1997'
    let reg3 = /\d+/g
    console.log(str3.match(reg3)) // [ '1987', '1997' ]
    
    reg3 = /\d/g
    console.log(str3.match(reg3)) // [ '1', '9', '8', '7', '1', '9', '9', '7' ]
    // 在量词元字符后面加 ? 则取消贪婪模式,按照最短结果来获取
    reg3 = /\d+?/g
    console.log(str3.match(reg3)) // [ '1', '9', '8', '7', '1', '9', '9', '7' ]
    

    相关文章

      网友评论

          本文标题:正则相关

          本文链接:https://www.haomeiwen.com/subject/wtotkhtx.html