代码之家  ›  专栏  ›  技术社区  ›  DjaouadNM

javascript-在字符串中保留匹配的正则表达式,直到没有匹配为止

  •  1
  • DjaouadNM  · 技术社区  · 7 年前

    TL;博士
    如何在字符串中搜索模式,并用可能再次出现模式的内容替换它,而不使用循环。

    在这种情况下,我需要搜索字符串中的某些模式,如下所示:

    1. 寻找 一、。 '(\-\-)+|(\+)+' 然后 (\+\-)+|(\-\+)+ 在整个字符串中并替换 一、。 + 二、。 具有 - .
    2. 再次检查字符串是否在两者之间 一、。 二、。 ,如果是,则中断,否则,转至步骤1。

    str

    var str = '1+-2--++--+4---++--+2';
    str.replace(/(\-\-)+|(\+)+/g,'+').replace(/(\+\-)+|(\-\+)+/g,'-');
    

    第一次替换后的字符串(第 () 是否只是为了突出显示更改,它们不是字符串的一部分):

    1(+)-2(--)(++)(--)(+)4(--)-(++)(--)(+)2 => 1(+)-2(+)(+)(+)(+)4(+)-(+)(+)(+)2
    

    第二次更换后:

    1(+-)2++++4(+-)+++2 => 1(-)2++++4(-)+++2
    

    ++++ -+ .
    我希望这样继续下去:

    1-2(++++)4-(+++)2 => 1-2(+)4-(+)2
    1-2(+)4(-+)2 => 1-2(+)4(-)2 => # and the final result 1-2+4-2
    


    3 回复  |  直到 5 年前
        1
  •  3
  •   trincot Jakube    7 年前

    一些分析表明 + - - ).

    这似乎是一种减少奇数序列的算法 - - ,和 +

    然而,如果这确实是所需的行为,则第二个正则表达式不应着眼于重复,而应一次仅替换一个发生变化的对,即 /(\+\-)|(\-\+)/g 而不是 /(\+\-)+|(\-\+)+/g .

    那么唯一的办法就是 是指序列中有奇数个,因为第一次替换只能删除偶数个,而第二次替换保持其数量不变。在所有其他情况下,一个序列的最终结果将是 .

    var str = '1+-2--++--+4---++--+2';
    
    var repl = str.replace(/\b(?=[+-])\+*(-\+*-\+*)*\b/g, '+')
                  .replace(/\b\+*-[+-]*/g, '-');
    
    console.log(repl);
        2
  •  2
  •   Will Barnwell user2481422    7 年前

    注: 我意识到这个答案基本上重复了trincot的答案,但我已经写了一半,然后在他的答案发布之前就去吃午饭了,我不喜欢浪费我的努力,而且我对不同的事情的解释略有不同。

    最终结果完全基于 -

    1. 偶数个 - +

      \+*(?:-\+*-\+*)*
      \+*              Zero or more '+'s
         (?:           Non-capturing group
            -            Exactly one '-'
             \+*         Zero or more '+'s
                -        Exactly one '-'
                 \+*     Zero or more '+'s
                    )* Repeat capture group Zero or more times
      
    2. - s(至少有一个相同的模式 - -

      \+*-\+*(?:-\+*-\+*)*
      

    但是,这里有一些陷阱。第一个正则表达式匹配一个空字符串,我们不想用+。我们可以通过向前看来解决这个问题,向前看可以验证正在测试的字符串是否匹配某个整体模式,而不消耗该字符串。

    (?=[+-]+)
    (?=       Positive lookahead
       [+-]     Either or '+' or '-'
           +    One or more times
            ) Close positive lookahead (rest of regex goes after this)
    

    [+-]+ 介于两个数字之间,因此第一个正则表达式可能会遇到以下情况:

    1++--+-2
    

    并找到匹配的字符串 ++--+ ,留给你

    1+-2
    

    \b ,或捕获正则表达式末尾的数字组,并结合对替换组中这些组的反向引用。我们将使用 \b 因为它是更简单、优雅和高效的解决方案。

    是一个特殊的正则表达式字符,它匹配字字符之间的零长度“边界” \w 和非文字字符 \W

    • 在字符串中的两个字符之间,其中一个是文字字符,另一个不是文字字符。[ Source

    var str = '1+--+-2--++--+4---++--+2';
    
    var repl = str.replace(/\b(?=[+-])\+*(-\+*-\+*)*\b/g, '+')
                  .replace(/\b\+*-\+*(?:-\+*-\+*)*\b/g, '-');
    
    console.log(repl);

    快捷方式

    \b[+-]{2,}\b
    

    因为在运行第一次替换后,任何由 + 大于长度1必须是那些与第一个正则表达式不匹配的,因此应替换为

    var str = '1+--+-2--++--+4---++--+2';
    
    var repl = str.replace(/\b(?=[+-])\+*(-\+*-\+*)*\b/g, '+')
                  .replace(/\b[+-]{2,}\b\b/g, '-');
    
    console.log(repl);
        3
  •  2
  •   user557597 user557597    7 年前

    编辑: 修复了的正则表达式

    (仅供参考-注意,即使这是一个单一的替换,它也使用回调。
    从好的方面来看,它仍然是使用双重替换的两倍。)

    我将保存这个以备下次使用,因为正则表达式是实心的,
    我见过几次这样的问题。


    这可以通过单个替换调用实现。

    \b(?:(?:\+|--)*(-(?!-)(?:\+|--)*)+|(?:\+|--)+)\b

     \b 
     (?:
          (?: \+ | -- )*                # optional positives
          (                             # (1 start), Neg (agressive)
               -                             # - sign
               (?! - )                       # not followed by a -
               (?: \+ | -- )*                # optional positives
          )+                            # (1 end)
       |                              # or,
          (?:                           # Pos (passive)
               \+
            |  --
          )+
     )
     \b 
    

    var str = ' 1+-2--++--+4---++--+2--6,,,,5--+--+5 ';
    
    console.log(
       str.replace(/\b(?:(?:\+|--)*(-(?!-)(?:\+|--)*)+|(?:\+|--)+)\b/g,
              function(m, g1) {return g1 ? '-' : '+';})
     );

    1-2+4-2+6,,,,5+5