js正则String.prototype.replace高级用法总结

304 阅读5分钟
  • 定义:replace() 方法返回一个新字符串,其中一个、多个或所有匹配的 pattern 被替换为 replacement

  • 语法:replace(pattern, replacement) 【 1、pattern:string | RegExp 2、replacement:string | Function 】

  • 用法梳理:

    • 1、基础用法: replacement 是个字符串,这是最基础的常见的用法,本文不在敖述
       const paragraph = "I think Ruth's dog is cuter than your dog!";
    
       console.log(paragraph.replace("Ruth's", 'my'));
       // Expected output: "I think my dog is cuter than your dog!"
    
       const regex = /Dog/i;
       console.log(paragraph.replace(regex, 'ferret'));
       // Expected output: "I think Ruth's ferret is cuter than your dog!"
    
    • 2、高阶用法:replacement 是个函数

      • 在只有一个匹配项时,这个函数会收到3个参数:与整个模式匹配的字符串、匹配项在字符串中的开始位置,以及整个字符串。在有多个捕获组的情况下,每个匹配捕获组的字符串也会作为参数传给这个函数,但最后两个参数还是与整个模式匹配的开始位置和原始字符串。这个函数应该返回一个字符串,表示应该把匹配项替换成什么
        • 那么怎么区分是3个参数还多个参数呢?

        • 正确的理解是:

          2-1、当pattern为正则,无分组,那么只有一个匹配,那么replacement就只会有三个参数;其定义为:function replacer(match, offset, originStr) {return replacement;} 【 无分组,只有三个参数 】

               function upperToHyphenLower(match, offset, string) {
                    // Remark: 这个地方match是匹配值,offset是偏移量,string是原字符串
                    // Expected output: 你将看到的匹配项 S 5 superStar
                    console.log("你将看到的匹配项", match, offset, string) 
          
                    return (offset > 0 ? "-" : "") + match.toLowerCase();
               }
          
               // Expected output: "super-star"    
               console.log("superStar".replace(/[A-Z]/g, upperToHyphenLower))
          

          2-2、当pattern为正则,且有捕获分组时,那么就是有多个参数;捕获组的个数有多少,额外参数就有多少,其定义为:function replacer(match, p1, p2, /* …, */ pN, offset, string, groups) {return replacement;} 【 其中p1, p2 .... pn 即为各个捕获组数据,和正则中的nn(1, 2....2 .... n)对齐 】

               function upperToHyphenLower(match, p1, offset, string) {
                    // Remark: 这个地方match是匹配值,p1是捕获组的值,offset是偏移量,string是原字符串
                    // Expected output: 你将看到的匹配项 S S 5 superStar
                    console.log("你将看到的匹配项", match, p1, offset, string) 
          
                    return (offset > 0 ? "-" : "") + match.toLowerCase();
               }
          
               // Expected output: "super-star"    
               console.log("superStar".replace(/([A-Z])/g, upperToHyphenLower))
          
  • 需要注意的事:

    • 1、对于正则的分组,有如下几种情况需要排查:

      • ( 被转义过的括号不算

      • (?:) 非捕获组的不算

      • [(] 放在方括号里面的小括号也不算,这也属于被转义过。

      这些情况下,正则分组标识符号 “(” 无效,被认为是无效分组

           // 无效分组,视为无分组,参数依然是三个
           function upperToHyphenLower(match, offset, string) {
                // Remark: 这个地方match是匹配值,offset是偏移量,string是原字符串
                
                // 正则全局,匹配多次,函数多次调用,依次替换
                // Expected output: 你将看到的匹配项 (A) 3 you(A)re(S)uper(S)tar
                // Expected output: 你将看到的匹配项 (S) 8 you(A)re(S)uper(S)tar
                // Expected output: 你将看到的匹配项 (S) 15 you(A)re(S)uper(S)tar
                console.log("你将看到的匹配项", match, offset, string) 
      
                return (offset > 0 ? "-" : "") + match.toLowerCase();
           }
      
           // Expected output: you-(a)re-(s)uper-(s)tar    
           console.log("you(A)re(S)uper(S)tar".replace(/\([A-Z]\)/g, upperToHyphenLower))
      
           /********************************************************************/
      
           // 无效分组,视为无分组,参数依然是三个
           function upperToHyphenLower(match, offset, string) {
                // Remark: 这个地方match是匹配值,offset是偏移量,string是原字符串
                
                // 正则全局,匹配多次,函数多次调用,依次替换
                // Expected output: 你将看到的匹配项 (A) 3 you(A)re(S)uper(S)tar
                // Expected output: 你将看到的匹配项 (S) 8 you(A)re(S)uper(S)tar
                // Expected output: 你将看到的匹配项 (S) 15 you(A)re(S)uper(S)tar
                console.log("你将看到的匹配项", match, offset, string) 
      
                return (offset > 0 ? "-" : "") + match.toLowerCase();
           }
      
           // Expected output: you-(a)re-(s)uper-(s)tar    
           console.log("you(A)re(S)uper(S)tar".replace(/[(][A-Z][)]/g, upperToHyphenLower))
      
           /********************************************************************/
      
           // 无效分组,视为无分组,参数依然是三个
           function upperToHyphenLower(match, offset, string) {
                // Remark: 这个地方match是匹配值,offset是偏移量,string是原字符串
                
                // 正则全局,匹配多次,函数多次调用,依次替换
                // Expected output: 你将看到的匹配项 (A) 4 you(A)re(S)uper(S)tar
                // Expected output: 你将看到的匹配项 (S) 9 you(A)re(S)uper(S)tar
                // Expected output: 你将看到的匹配项 (S) 16 you(A)re(S)uper(S)tar
                console.log("你将看到的匹配项", match, offset, string) 
      
                return (offset > 0 ? "-" : "") + match.toLowerCase();
           }
      
           // Expected output: you(-a)re(-s)uper(-s)tar 
           console.log("you(A)re(S)uper(S)tar".replace(/(?:[A-Z])/g, upperToHyphenLower))
      
    • 2、当replacement是函数时,如果第一个参数中的正则表达式是全局的,那么为了替换每个完全匹配的字符串,该函数将被多次调用

      这种情况下,无论回调函数时多少个参数,都会多次执行

           // 无分组,三个参数时
           function upperToHyphenLower(match, offset, string) {
                // Remark: 这个地方match是匹配值,offset是偏移量,string是原字符串
                
                // 正则全局,匹配多次,函数多次调用,依次替换
                // Expected output: 你将看到的匹配项 A 3 youAreSuperStar
                // Expected output: 你将看到的匹配项 S 6 youAreSuperStar
                // Expected output: 你将看到的匹配项 S 11 youAreSuperStar
                console.log("你将看到的匹配项", match, offset, string) 
      
                return (offset > 0 ? "-" : "") + match.toLowerCase();
           }
      
           // Expected output: "you-are-super-star"    
           console.log("youAreSuperStar".replace(/[A-Z]/g, upperToHyphenLower))
      
           /********************************************************************/
           
           // 有分组,多个参数时
           function upperToHyphenLower(match, p1, offset, string) {
                // Remark: 这个地方match是匹配值,p1是捕获组的值,offset是偏移量,string是原字符串
                
                // 正则全局,匹配多次,函数多次调用,依次替换
                // Expected output: 你将看到的匹配项 A A 3 youAreSuperStar
                // Expected output: 你将看到的匹配项 S S 6 youAreSuperStar
                // Expected output: 你将看到的匹配项 S S 11 youAreSuperStar
                console.log("你将看到的匹配项", match, p1, offset, string) 
      
                return (offset > 0 ? "-" : "") + match.toLowerCase();
           }
      
           // Expected output: "you-are-super-star"    
           console.log("youAreSuperStar".replace(/([A-Z])/g, upperToHyphenLower))
      
  • 使用场景:

    • 低代码和泛低代码工程

      • 低代码本质上,是将用户配置的字符串配置,给予转换执行,低代码工程注定对字符串的操作比较多,有些就会牵涉到高级一点的正则匹配替换
       // lowcode-engine use demo
       const RE_CAMEL = /[A-Z]/g;
       const RE_HYPHEN = /[-\s]+(.)?/g;
      
       function hyphenate(str: string): string {
            return str.replace(RE_CAMEL, w => `-${w}`).toLowerCase();
       }
      
       function camelize(str: string): string {
            return str.replace(RE_HYPHEN, (m, w) => (w ? w.toUpperCase() : ''));
       }
      
  • 参考: