每隔一次匹配

时间:2009-02-26 08:41:29

标签: regex

有没有办法指定正则表达式来匹配字符串中每个第二次出现的模式?

实施例

  • 针对字符串 abcdabcd 搜索 a 应该会在第5位找到一个匹配项
  • 针对字符串 abcdabcd 搜索 ab 应该会在第5位找到一个匹配项
  • 针对字符串 abcdabcd 搜索 dab 应该会发现没有出现
  • 搜索 a 对抗字符串 aaaa 应该会在第2和第4位发现两次事件

6 个答案:

答案 0 :(得分:54)

使用分组。

foo.*?(foo)

答案 1 :(得分:9)

假设您想要的模式是abc + d。您希望在字符串中匹配此模式的第二次出现。

您将构建以下正则表达式:

abc+d.*?(abc+d)

这将匹配表单的字符串:<your-pattern>...<your-pattern>。既然我们正在使用不情愿的限定符*?我们很安全,两者之间不可能有另一场比赛。使用几乎所有正则表达式实现提供的匹配器组,然后将在括号内的组中检索您想要的字符串。

答案 2 :(得分:6)

如果你正在使用C#,你可以一次获得所有匹配(即使用Regex.Matches(),返回MatchCollection,并检查项目的索引:index % 2 != 0 )。

如果要查找替换它的匹配项,请使用Regex.Replace()的一个重载使用MatchEvaluator(例如Regex.Replace(String, String, MatchEvaluator)。这是代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "abcdabcd";

            // Replace *second* a with m

            string replacedString = Regex.Replace(
                input,
                "a",
                new SecondOccuranceFinder("m").MatchEvaluator);

            Console.WriteLine(replacedString);
            Console.Read();

        }

        class SecondOccuranceFinder
        {
            public SecondOccuranceFinder(string replaceWith)
            {
                _replaceWith = replaceWith;
                _matchEvaluator = new MatchEvaluator(IsSecondOccurance);
            }

            private string _replaceWith;

            private MatchEvaluator _matchEvaluator;
            public MatchEvaluator MatchEvaluator
            {
                get
                {
                    return _matchEvaluator;
                }
            }

            private int _matchIndex;
            public string IsSecondOccurance(Match m)
            {
                _matchIndex++;
                if (_matchIndex % 2 == 0)
                    return _replaceWith;
                else
                    return m.Value;
            }
        }
    }
}

答案 3 :(得分:2)

会像

(pattern.*?(pattern))*

为你工作?

编辑:

这个问题在于它使用非贪婪的运算符*?,这可能需要沿着字符串进行大量的回溯,而不是只查看每个字母一次。这对你意味着什么,这对于大的差距来说可能是缓慢的。

答案 4 :(得分:2)

返回引用可以在这里找到有趣的解决方案。这个正则表达式:

([a-z]+).*(\1)

将找到最长的重复序列。

这个将找到重复的3个字母的序列:

([a-z]{3}).*(\1)

答案 5 :(得分:0)

没有“直接”的方式,但您可以指定模式两次:a[^a]*a匹配第二个“a”。

另一种方法是使用您的编程语言(perl?C#?...)来匹配第一次出现,然后是第二次出现。

编辑:我看到其他人使用“非贪婪”操作符进行了回复,这可能是一个很好的方法,假设你在你的正则表达式库中有它们!