Подтвердить что ты не робот

Матч при каждом втором появлении

Есть ли способ указать регулярное выражение для соответствия каждому второму вхождению шаблона в строке?

Примеры

  • поиск a для строки abcdabcd должен найти одно вхождение в позиции 5
  • поиск ab по строке abcdabcd должен найти одно вхождение в позиции 5
  • поиск dab для строки abcdabcd не должен содержать вхождения
  • поиск a по строке aaaa должен найти два входа в позициях 2 и 4
4b9b3361

Ответ 1

Используйте группировку.

foo.*?(foo)

Ответ 2

Предположим, что вам нужен шаблон abc + d. Вы хотите совместить второе вхождение этого шаблона в строке.

Вы создадите следующее регулярное выражение:

abc+d.*?(abc+d)

Это будет соответствовать строкам формы: <your-pattern>...<your-pattern>. Поскольку мы используем неохотный квалификатор *? мы в безопасности, что между ними не может быть другого совпадения. Используя группы сопряжений, которые в значительной степени реализуют все реализации регулярных выражений, вы затем извлекаете строку в группе в скобках, которая вам нравится.

Ответ 3

Если вы используете С#, вы можете либо получить все совпадения одновременно (т.е. использовать 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;
            }
        }
    }
}

Ответ 4

Было бы что-то вроде

(pattern.*?(pattern))*

работа для тебя?

Редактировать:

Проблема в том, что он использует не жадный оператор *? , что может потребовать очень много возврата по строке вместо того, чтобы просто смотреть на каждую букву один раз. Это означает, что это может быть медленным для больших промежутков.

Ответ 5

Обратные ссылки могут найти интересные решения здесь. Это регулярное выражение:

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

найдет самую длинную повторяющуюся последовательность.

В этой последовательности будет повторяться последовательность из трех букв:

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

Ответ 6

Нет никакого "прямого" способа сделать это, но вы можете указать шаблон дважды, как в: a[^a]*a, которые совпадают со вторым "a".

Альтернативой является использование вашего языка программирования (perl? С#?...) в соответствии с первым вступлением, а затем вторым.

EDIT. Я видел, как другие ответили, используя "неживые" операторы, которые могли бы быть хорошим способом, предполагая, что вы их используете в своей библиотеке регулярных выражений!