• RegExp重学与整理


    什么是正则表达式

    Regular Expression 使用单个字符串来描述、匹配一系列符合某个句法规则的字符串
    按照某一种规则去匹配符合条件的字符串

    修饰符

    g

    名称:global

    说明:全文搜索,不添加的话,搜索到第一个匹配停止

    i

    名称:ignore case

    说明:忽略大小写,默认大小写敏感

    m

    名称:multiple linse

    说明:执行多行匹配

    元字符

    1. 正则表达式由两种基本字符类形成:
      原义文本字符
      元字符
    2. 元字符是在正则表达式中有特殊含义的非字母字符
    * + ? $ ^ . |  / : = ( ) { } [ ] 
    
    字符 含义
    水平制表符
    v 垂直制表符
    换行符
    回车符
    o 空字符
    f 换页符
    cX 与X对应的控制字符(Ctrl+X)
    xnn 由十六进制数nn指定的拉丁字符,列如:x0A等价于
    uxxxx 由十六进制数xxxx指定的Unicode 字符,列如u0009等价于

    字符类

    • 我们可以使用元字符 [] 来构建一个简单的类
    • 所谓类是指符合某些特性对象,一个泛指,而不是特指某个字符
    • 表达式[abc] 把字符 abc 归为一类,表达式可以匹配这类的字符
      var reg = /[abc]/g
      '1a6c1d6v5d1b5'.replace(reg, 'X')
      // "1X6X1d6v5d1X5"
      // 我们将当前字符串中的abc 替换成了X
    

    字符类取反

    • 使用元字符 ^ 创建反向类/负向类
    • 反向类的意思是不属于某类的内容
    • 表达式 [^abc] 表示,不是字符a 或 b 或 c 的内容
      var reg = /[^abc]/g
      '1a6c1d6v5d1b5'.replace(reg, 'X')
      // "XaXcXXXXXXXbX"
      // 我们将当前字符串中不是abc的所有内容 替换成了X
    

    范围类

    • 我们可以使用 [a-z] 来连接两个字符表达式从a到z的任意字符,这是一个闭区间,也就包含a和z本身。
      var reg = /[a-z]/g
      'a1b2c3d45z3x'.replace(reg, 'Y')
      // "Y1Y2Y3Y45Y3Y"
      // a-z的所有字符替换为Y
    
    
      // 范围类也可以连这写
      var reg = /[a-zA-Z]/g
      'QDa1B2c3d45Z3xASDK'.replace(reg, 'Y')
      // "YYY1Y2Y3Y45Y3YYYYY"
      // a-z和A-Z的所有字符替换为Y
    
    
      // 如果我们在范围类中,比如说需要匹配这样的 8375-32*29 将-以及小于我的全部替换成Y
      var reg = /[1-5-]/g
      '8375-32*29'.replace(reg, 'Y')
      // "8Y7YYYY*Y9"
    

    字符类

    字符 等价类 含义
    . [^ ] 除了回车和换行符之外的所有字符
    d [0-9] 查找数字
    D [^0-9] 非数字字符
    s [ x0Bf ] 空白符
    S [^ x0Bf ] 非空白符
    w [a-zA-Z_0-9] 字母 数字 下划线
    W [^a-zA-Z_0-9] 非单词字符
    [...] 方括号内的任意字符
    [^...] 不在方括号内的任意字符
    [] 退格直接量(特列)

    边界

    字符 含义
    ^ 以xxx开始
    $ 以xxx结尾
     单词边界
    B 非单词边界
    (?=p) 零宽正向先断言,要求接下来的字符都与p匹配,但不能包括匹配p的那些字符
    (?!p) 零宽负正先行断言,要求接下来的字符不与p匹配

    量词

    量词 含义
    {n} 匹配前一项n次
    {n,m} 匹配前一项至少n次,但不能超过m次
    {n,} 匹配前一项n次或者更多次
    + 出现一次或多次 (最少出现一次)等价于{1,}
    * 出现零次或多次 (任意次)等价于{0,}
    ? 出现零次或一次(最多出现一次)

    贪婪模式

      var reg = /d{3,6}/g
      '12345678'.replace(reg, 'X')
      // X78 
      // 他匹配了123456 而78没有被匹配
      // 我们这个正则表达式 是匹配3-6次,可以满足3 4 5 6 都可以满足,而这时候正则表达会尽可能多的匹配,直到匹配失败
      // 
    

    非贪婪模式

    让正则表达式尽可能少的匹配,一旦成功匹配不再继续尝试就是非贪婪模式。
    做法很简单,只要再量词后面加上即可

      var reg = /d{3,6}?/g
      '12345678'.replace(reg, 'X')
      // XX78
      // 他匹配了 123 456
      // 3 次一组,后面两个没有被匹配掉
    

    分组

    使用()可以达到分组的功能,使量词作用与分组

      var reg = /([a-z]d){3}/g
      'a1b2c3d4'.replace(reg, 'X')
      // Xd4
    
    
      // 在使用或的时候,我们同样需要分组
      var reg = /(java|type)script/g
      'javascripttypescript'.replace(reg, 'X')
      // XX
    

    反向引用

      var reg = /(d{2})-(d{2})-(d{4})/g
      '02-13-2020'.replace(reg, '$3/$1/$2')
      // 2020/02/13
      // 他会捕获每一个分组,分别从$1-$n
    

    忽略分组

    不希望捕获某些分组,我们只需要再分组内加上?:就可以

      var reg = /(?:d{2})-(d{2})-(d{4})/g
      '02-13-2020'.replace(reg, '$3/$1/$2')
      // $3/13/2020
      // 我们可以看到我们只有$1 和 $2 捕获到了
    

    前瞻

    • 正则表达式从文本头部向尾部开始解析,文本尾部方向,称为: 文本尾部叫做
    • 前瞻就是在正则表达式匹配到的规则的时候,向前检查是否符合断言(断言就是前瞻语法的一部分),后顾/后瞻方向相反。
    • 前瞻比如:当我们匹配到一个人叫张三的时候,我们还需要往前看看他爸爸是否叫张二
    • JavaScript 不支持后顾
    • 符合和不符合特定断言称为肯定/正向匹配和否定/负向匹配
    名称 正则 含义
    正向前瞻 exp(?=assert)
    负向前瞻 exp(?!assert)
    正向后顾 exp(?<=assert) JavaScript 不支持
    负向后顾 exp(?<!assert) JavaScript 不支持
      // 正向前瞻
      // 匹配单词字符,并且要求后面需要是数字
      var reg = /w(?=d)/g
      'a2*3'.replace(reg, 'X')
      // X2*3
      'a2*3dasd2e5'.replace(reg, 'X')
      // X2*3dasX2X5
    
      // 负向前瞻
      var reg = /w(?!d)/g
      'a2*3'.replace(reg, 'X')
      // aX*X
      'a2*3dasd2e5'.replace(reg, 'X')
      // "aX*XXXXdXeX"
    

    Js 正则 对象属性

    每一个RegExp对象都包含5个属性。

    • global:是否全文搜索, 默认 false
    • ignore case:是否大小写敏感,默认 false
    • multiline: 多行搜索,默认值是 false
    • lastIndex: 当前匹配结果的 最后一个字符的 下一个字符
    • source:source是一个只读的字符串,包含正则表达式的文本。
    var reg1 = /w/
    var reg2 = /w/gim
    
    reg1.global false
    reg1.ignoreCase false
    reg1.multiline false
    reg1.global = true 这是不起作用的
    reg1.global false
    
    reg2.global true
    reg2.ingnoreCase true
    reg2.multiline true
    
    reg1.source "w"
    reg2.source "w"
    
    reg1.lastIndex 0
    reg2.source 0
    
    

    Js 正则 方法

    test

    • 用于测试字符串参数中是否存在匹配正则表达式模式的字符串
    • 如果存在则返回 true,否则返回 false
    var reg1 = /w/
    var reg2 = /w/g
    reg1.test('a') true
    reg1.test('|') false
    reg1.test(')') false
    // 判断当前字符串 是否包含传递的值
    

    当我们加上g的时候 我们多执行几次结果,会反向奇怪的现象
    我们来开一个有意思的例子:

    reg2.test('ab')  true
    console.log(reg2.$1)
    reg2.test('ab')  true
    reg2.test('ab')  false
    reg2.test('a')  true
    reg2.test('a')  false
    /*
    原因:这个其实是lastIndex在作怪
    reg2.test('ab') 拆分
    第一遍执行 我们找当前匹配结果 a,a所在字符的位置是1,所以lastIndex = 1
    第二遍执行 当前匹配结果的最后一个字符 的下一个字符 b,b所在字符位置是2,所以lastIndex = 2
    第三遍执行的时候 后面没有可以匹配到的字符了 所以返回为false 并且将 lastIndex1 重置为 0 
    所以第四次匹配的时候,他有开始重新查找 返回为true
    
    注意: 每次匹配的时候,他把上一个结果记住了,从下一个开始
    */
    

    解决方法:

      // 每次都实列化一个新的
      (/w/g).test('a')
    

    exec

    • 使用正则表达式模式对字符串执行搜索,并将更新全局RegExp对象的属性以反映匹配结果。
    • 如果没有匹配到文本返回null,否则返回一个结果数组:
      • index 表示匹配结果第一个字符的位置
      • input 存放被检索的字符串 string
    非全局调用
    • 调用非全局的RegExp对象的exec() 时,返回数组
    • 第一个元素是与正则表达式相匹配的文本
    • 第二个元素是与RegExpObject 的第一个子表达式相匹配的文本(如果有的话)
    • 第三个元素与RegExp 对象的第二个子表达式相匹配的文本(如果有的话),以些类推
    var reg1 = /d(w)d/;
    var reg2 = /d(w)d/g;
    var str = '1a2b3c4d5e'
    var ret = reg1.exec(str)
    console.log(`${reg1.lastIndex} 	 ${ret.index} 	 ${ret}`)
    
    // lastIndex在全局里面才显示
    // index 从第几个字符开始匹配
    // [匹配结果, 分组]
    // 0 	 0 	 ["1a2", "a"]
    console.log(`${reg1.lastIndex} 	 ${ret.index} 	 ${ret}`)
    // 0 	 0 	 1a2,a
    while(ret = reg2.exec(str)) {
      console.log(`${reg2.lastIndex} 	 ${ret.index} 	 ${ret.toString()}`)
      // 3 	 0 	 1a2,a
      // 7 	 4 	 3c4,c
      /** lastIndex
      第一次匹配,1a2 lastIndex 索引记录到 3
      第二次匹配,3c4 lastIndex 索引记录到 7
      */
      /** index
      第一次匹配,当前匹配到的,第0向开始
      第二次匹配,当前匹配到的,第4向开始
      */
    }
    
    

    正则表达式的字符串方法

    • search 方法用于检索字符串中指定的字符串,或检索与正则表达式相匹配的子字符串
    • 方法返回第一个匹配结果 index,查不到返回 -1
    • search 方法不执行全局匹配,它将忽略标志g,并且总是从字符串的开头进行检索
    'a1b2c3d4e1'.search('1') 1
    'a1b2c3d4e1'.search('10') -1
    
    'a1b2c3d4e1'.search(1) 1
    // 为什么 写数字1 也可以呢
    // 原因:我们传递的参数不是正则的时候,他就尝试将我们传递的参数转换为正则。
    
    'a1b2c3d4e1'.search(/1/) 1
    'a1b2c3d4e1'.search(/1/g) 1 
    // 开启全局模式和不开启全局模式,结果都一样
    

    match

    • match 方法将检索字符串,以找到一个或多个与regexp匹配的文本
    • regexp 是否具有标志g 对结果影响很大
    非全局调用
    • 如果regexp没有标志g,那么match 方法就只能在字符串中执行一次匹配
    • 如果没有找到任何匹配的文本,将返回null
    • 否则它将返回一个数组,其中存放了与找到的文本匹配文本有关的信息
    • 返回数组的第一个元素存放的是匹配文本,而其余的元素存放的是与正则表达式的子表达式匹配的文本
    • 除了常规的数组元素之外,返回的数组还包含有 2个对象属性
      • index 生命匹配文本的起始字符在字符串的位置
      • input 生明对stringObject的引用
    var reg1 = /d(w)d/
    var str = 'a1b2c3d4e5'
    var ret = str.match(reg1)
    ret ["1b2", "b"]
    ret.index 1
    reg1.lastIndex 0
    
    全局调用
    • 如果 regexp 具有标志 g 则 match 方法将执行全局检索,找到字符串中的所有匹配字符串
      • 没有找到任何匹配的字符串,则返回null
      • 如果找到了一个或多个匹配字符串,则返回一个数组
    • 数组元素中存放的是字符串中所有的匹配字符串,而且也没有index属性或input 属性
    var reg2 = /d(w)d/g
    var str = 'a1b2c3d4e5'
    var ret = str.match(reg2)
    ret ["1b2", "3d4"]
    ret.index undefined
    reg2.lastIndex 0
    

    splic

    • 我们经常使用 split 方法把字符串分割为字符数组
    'a,b,c,d'.split(','); // ['a', 'b', 'c', 'd']
    
    • 在一些复杂的分割情况下,我们还可以使用正则表达式解决
    'a1b2c3d'.split(/d/); // ["a", "b", "c", "d"]
    

    说明: split 其实默认也是给我们尝试转成正则表达式 /,/

    replace

    • 参数1 string | reg 找谁
    • 参数2 string | function 替换成谁
      • function 会在每次匹配替换的时候调用,有四个参数 (注意:参数不固定)
        1. 匹配字符串
        2. 正则表达式分组内容,没有分组则没有该参数
        3. 匹配项在字符串中的index
        4. 原字符串
    'a1cde'.replace('1', 'b') // abcde
    'a1cde'.replace(/d/, 'b') // abcde
    
    'a1b2c3d4'.replace(/d/g, (match, index, origin)=>{
      return parseInt(match) + 1
    }) // a2b3c4d5
    
    
    'a1b2c3d4'.replace(/(d)(w)(d)/g, (match, group1, group2, group3, index, origin)=>{
      console.log(group1, group2)
      return group1 + group3
    }) // a12c34
    
    
  • 相关阅读:
    多线程编程之线程死锁问题 转载
    线程的挂起和恢复 转载
    redis 内存库设置 教你怎么解决64位Windows版Redis狂占C盘的问题.
    MSSQL数据库分区表
    如何将桌面的路径定义到其它盘符,如d:users桌面
    sqlserver数据库脱机时发生异常:由于无法在数据库 'SMS' 上放置锁,ALTER DATABASE 失败。请稍后再试。 ALTER DATABASE 语句失败。 (.Net SqlClient Data Provider)
    JAVA代码反编译笔记
    SQLServer—系统中的内存配置
    .net remoting 客户端与服务端绑定事件,一部电脑当服务器,另一部当客户端,发布后没法接收远程错误信息。
    Java Socket 模拟HTTP请求
  • 原文地址:https://www.cnblogs.com/wangyong1997/p/14074932.html
Copyright © 2020-2023  润新知