【问题标题】:How to match an even number of any character in a string?如何匹配字符串中任意字符的偶数个?
【发布时间】:2022-02-13 07:54:38
【问题描述】:

我有一个字符串:

aaabbashasccddee

我想得到偶数个连续相同字符的匹配。例如,从上面的字符串中,我想要这些匹配:

[bb],[cc],[dd],[ee]

我已经尝试过这个解决方案,但它甚至不接近:

"^(..)*$

【问题讨论】:

  • 你有很多这样的帖子。你到底想达到什么目的?
  • @John 为什么,这有问题吗?
  • 在我看来,您只是在零敲碎打地尝试构建一些东西,而当您寻求帮助时,让我们了解更大的图景可能会更好。可能有更好的方法来做任何你想做的事情。

标签: c# regex


【解决方案1】:

幸运的是 .NET 正则表达式能够处理无限后视。使用以下正则表达式可以实现您所需要的:

((?>(?(2)(?=\2))(.)\2)+)(?<!\2\1)(?!\2)

live demo here

正则表达式分解:

  • ( 捕获组 #1 的开始
    • (?&gt; 非捕获组的开始(原子)
      • (?(2) 如果设置了捕获组#2
        • (?=\2)下一个字符应该是它
      • )end f 条件
      • (.)\2匹配并捕获一个字符并再次匹配(偶数)
    • )+ 尽可能重复,至少一次
  • ) 捕获组 #1 结束
  • (?&lt;!\2\1) 这是诀窍。后视告诉引擎,比我们目前匹配的更早出现的前一个字符不应该是存储在捕获组 #2 中的相同字符
  • (?!\2) 下一个字符不应与存储在捕获组#2 中的字符相同

更新:

因此,您可以在 C# 中执行以下代码,以通过 Regex 获取字符串中的所有偶数序列字符,而无需任何其他运算符(纯正则表达式)。

var allEvenSequences = Regex.Matches("aaabbashasccddee", @"((?>(?(2)(?=\2))(.)\2)+)(?<!\2\1)(?!\2)").Cast<Match>().ToList();

另外,如果您想制作[bb],[cc],[dd],[ee],那么您可以加入该序列数组:

string strEvenSequences = string.Join(",", allEvenSequence.Select(x => $"[{x}]").ToArray());
//strEvenSequences will be [bb],[cc],[dd],[ee]

【讨论】:

    【解决方案2】:

    另一种可能的不涉及条件的纯正则表达式解决方案:

    (.)(?<!\1\1)\1(?:\1\1)*(?!\1)
    

    细分:

    (.)         # First capturing group - matches any character.
    (?<!\1\1)   # Negative lookbehind - ensures the matched char isn't preceded by the same char.
    \1          # Match another one of the character in the 1st group (at least two in total).
    (?:\1\1)    # A non-capturing group that matches two occurrences of the same char.
    *           # Matches between zero and unlimited times of the previous group.
    (?!\1)      # Negative lookahead to make sure no extra occurrence of the char follows.
    

    演示:

    string input = "aaabbashasccddee";
    string pattern = @"(.)(?<!\1\1)\1(?:\1\1)*(?!\1)";
    var matches = Regex.Matches(input, pattern);
    foreach (Match m in matches)
        Console.WriteLine(m.Value);
    

    输出:

    bb
    cc
    dd
    ee
    

    Try it online.

    【讨论】:

    • 这是黄金。我喜欢这个主意。 +1
    • @revo 非常感谢 :-) 在问题发布几分钟后,我实际上正在研究它,但是一旦问题得到了有效解决方案的答案(现已删除),我就放弃了它。然后,当 OP 要求提供纯正则表达式解决方案并且我看到了您的答案(这很好,顺便说一句)时,我说“好吧,让我也发布我的版本”:-D
    • @AhmedAbdelhameed (?&gt;..)(?&lt;..) 有什么区别请告诉我
    • @Alex (?&gt;..) 是一个atomic group(阅读更多关于它的here),而(?&lt;..) 是一个Lookbehind,它可以是积极的(即(?&lt;=..))或消极的(即(?&lt;!..))。在 revo 的答案中使用(并命名)了原子组和 Lookbehind,而我的只使用了 Lookbehind。提示:检查此评论中的所有链接。它们非常有用,你会学到很多东西。祝你好运! :-)
    • @Alex 否定的 Lookbehind 意味着 next 字符必须not 前面是 Lookbehind 中的内容。请阅读我提供的文章以了解更多信息。 Here's another great answer 解释了 Lookaheads、Lookbehinds 和 atomic groups。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-23
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多