【问题标题】:Reduce multiple consecutive equal characters from a string to just one将字符串中的多个连续相等字符减少为一个
【发布时间】:2013-05-13 21:18:39
【问题描述】:

基本上,我想取一个字符串,如果连续有多个'+',我想删除除一个之外的所有。所以:

"This++is+an++++ex+ampl++e"

会变成

"This+is+an+ex+ampl+e"

我不确定 LINQ 或 Regex 或其他方法是否最适合,但它不必使用任何特定方法。

【问题讨论】:

    标签: c# regex linq replace


    【解决方案1】:
    Regex.Replace(str, @"\++", "+");
    

    【讨论】:

    • 该正则表达式的结果不会只是"This+is+an++ex+ampl+e" 吗?它将用 + 替换每个 ++,但不会将 +++ 或 ++++(等)修复为 +。如果我错了,请纠正我。
    • @sammy_winter:不; + 是修饰符。 (这就是为什么我需要一个反斜杠)
    • 详细来说,第一个+,被转义,表示实际的加号,第二个+,表示“一个或多个前一个字符”。因此,它将匹配一个到任意数量的连续加号,并用一个加号替换它们。这就是你想要的。
    • 可能不会对速度产生可衡量的影响,但我会这样做 \+\++ 这样我就只会在有多个 + 的地方替换。
    • @TimS。如果你打算做所有这些,为什么不\+{2,}?我觉得我们在这里分不清,但就可维护性而言,我发现\++ 比我们的任何一个答案都更具可读性。
    【解决方案2】:
    while (str.Contains("++"))
        str = str.Replace("++", "+");
    

    【讨论】:

      【解决方案3】:

      Microsoft 的Interactive Extensions (Ix) 有一个名为DistinctUntilChanged 的方法可以满足您的需求。该库中包含许多有用的功能 - 但它另一个完整的库,您可能不想打扰。

      用法如下:

      str = new string(str
          .ToEnumerable()
          .DistinctUntilChanged()
          .ToArray());
      

      如果您只想删除加号,那么您可以这样做:

      str = new string(str
          .ToEnumerable()
          .Select((c, i) => new { c, i = (c != '+' ? i : -1) })
          .DistinctUntilChanged()
          .Select(t => t.c)
          .ToArray());
      

      【讨论】:

      • 为什么有人会反对这个?这是一个完全合法的解决方案,使用很可能包含在未来版本的 .NET 中的 Microsoft 扩展库。
      • 可能是因为我们没有使用单行解决方案,而在此处使用正则表达式会创建更清晰的代码。但我也不知道为什么我也投了反对票。
      • 是的,但投反对票的是不正确的答案、误导的答案或一般无用的答案。我个人不喜欢 Regex(我敢肯定还有很多其他人),这提供了一种 LINQ 风格的替代方案。投票滥用在 SO 上如此普遍,这很烦人......
      • 我喜欢正则表达式来处理这种相对简单的情况,但它几乎从来都不是最快的方法。我认为我们的两个答案虽然涉及更多代码,但可能更快,并且看起来正确且相关。也许downvotes应该需要评论解释downvote。
      【解决方案4】:

      有一些方法可以用更少的代码做到这一点(@slaks 向我展示了我需要重新学习正则表达式的程度),但如果你经常这样做,这在大多数情况下应该尽可能快。

      public static string RemoveDupes(this string replaceString, char dupeChar){
          if(replaceString == null || String.Length < 2){ return replaceString; }
          int startOfGood = 0;
          StringBuilder result = new StringBuilder();
          for(int x = 0;x<replaceString.Length-1;x++){
              if(replaceString[x] == dupeChar && replaceString[x+1] == dupeChar){
                  result.Append(replaceString.SubString(startOfGood,x-startOfGood));//I think this works with length 0
                  startOfGood = x+1;
              }
          }
          result.Append(replaceString.Substring(startOfGood,
                         replaceString.Length-startOfGood));
          return result.ToString();
      }
      //Usage: 
      var noDupes = "This++is+an++++ex+ampl++e".RemoveDupes('+');
      

      【讨论】:

      • 虽然这似乎比正则表达式更快(至少在测试字符串上),但它有一个致命的缺陷。你得到一个带有字符串"This++is++a++test++"的索引超出范围异常
      • @JimMischel 真的。我修复了它以考虑以 ++ 开头或结尾的字符串。
      • 为了使其尽可能快,您应该预先设置 StringBuilder 的大小。
      • 有一个更简洁、速度更快的解决方案。见blog.mischel.com/2013/05/13/…。但除非我真的需要速度,否则我只会使用正则表达式。
      • @SLaks 是的,在大多数情况下,用起始字符串的大小调整 StringBuilder 的速度会稍微快一些(例外是一个长字符串,主要是欺骗),但这似乎足够好,可以更快比正则表达式。无论哪种方式,我认为您的正则表达式解决方案在 90% 以上的情况下都更好,我只是喜欢考虑速度。
      猜你喜欢
      • 2022-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-15
      相关资源
      最近更新 更多