Нужно регулярное выражение для соответствия особым ситуациям - PullRequest
2 голосов
/ 18 мая 2010

Я отчаянно ищу регулярные выражения, соответствующие этим сценариям:

1) Совпадение чередующихся символов

У меня есть строка типа «Это моя строка foobababababaf» - и я хочу соответствовать «babababa»

Единственное, что я знаю, это длина фрагмента для поиска - я не знаю, какие это могут быть символы / цифры - но они чередуются.

Я действительно понятия не имею, с чего начать: (

2) Совпадение объединенных групп

В строке типа «Это моя строка foobaafoobaaaooo» - и я хочу соответствовать «aaaooo». Как и в 1) Я не знаю, какие это могут быть символы или цифры. Знаю только, что они появятся в двух группах.

Я экспериментировал с использованием (.) \ 1 \ 1 \ 1 (.) \ 1 \ 1 \ 1 и подобных вещей ...

Ответы [ 4 ]

3 голосов
/ 18 мая 2010

Я думаю, что-то вроде этого - то, что вы хотите.

Для чередующихся символов:

(?=(.)(?!\1)(.))(?:\1\2){2,}

\0 будет всей чередующейся последовательностью, \1 и \2 являются двумя (различными) чередующимися символами.

Для набора символов N и M, возможно разделенных другими символами (замените N и M числами здесь):

(?=(.))\1{N}.*?(?=(?!\1)(.))\2{M}

\0 будет весь матч, включая инфикс. \1 символ повторяется (по крайней мере) N раз, \2 символ повторяется (по крайней мере) M раз.

Вот тестовый набор на Java.

import java.util.regex.*;

public class Regex3 {
    static String runNrunM(int N, int M) {
        return "(?=(.))\\1{N}.*?(?=(?!\\1)(.))\\2{M}"
            .replace("N", String.valueOf(N))
            .replace("M", String.valueOf(M));
    }
    static void dumpMatches(String text, String pattern) {
        Matcher m = Pattern.compile(pattern).matcher(text);
        System.out.println(text + " <- " + pattern);
        while (m.find()) {
            System.out.println("  match");
            for (int g = 0; g <= m.groupCount(); g++) {
                System.out.format("    %d: [%s]%n", g, m.group(g));
            }
        }
    }
    public static void main(String[] args) {
        String[] tests = {
            "foobababababaf foobaafoobaaaooo",
            "xxyyyy axxayyyya zzzzzzzzzzzzzz"
        };
        for (String test : tests) {
            dumpMatches(test, "(?=(.)(?!\\1)(.))(?:\\1\\2){2,}");
        }
        for (String test : tests) {
            dumpMatches(test, runNrunM(3, 3));
        }
        for (String test : tests) {
            dumpMatches(test, runNrunM(2, 4));
        }
    }
}

Это дает следующий вывод:

foobababababaf foobaafoobaaaooo <- (?=(.)(?!\1)(.))(?:\1\2){2,}
  match
    0: [bababababa]
    1: [b]
    2: [a]
xxyyyy axxayyyya zzzzzzzzzzzzzz <- (?=(.)(?!\1)(.))(?:\1\2){2,}
foobababababaf foobaafoobaaaooo <- (?=(.))\1{3}.*?(?=(?!\1)(.))\2{3}
  match
    0: [aaaooo]
    1: [a]
    2: [o]
xxyyyy axxayyyya zzzzzzzzzzzzzz <- (?=(.))\1{3}.*?(?=(?!\1)(.))\2{3}
  match
    0: [yyyy axxayyyya zzz]
    1: [y]
    2: [z]
foobababababaf foobaafoobaaaooo <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{4}
xxyyyy axxayyyya zzzzzzzzzzzzzz <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{4}
  match
    0: [xxyyyy]
    1: [x]
    2: [y]
  match
    0: [xxayyyy]
    1: [x]
    2: [y]

Объяснение

  • (?=(.)(?!\1)(.))(?:\1\2){2,} состоит из двух частей
    • (?=(.)(?!\1)(.)) устанавливает \1 и \2, используя lookahead
      • Вложенный отрицательный прогноз гарантирует, что \1! = \2
      • Использование перехватчика для захвата позволяет \0 иметь полное совпадение (а не только "хвостовой" конец)
    • (?:\1\2){2,} фиксирует последовательность \1\2, которая должна повторяться как минимум дважды.
  • (?=(.))\1{N}.*?(?=(?!\1)(.))\2{M} состоит из трех частей
    • (?=(.))\1{N} захватывает \1 в перспективе, а затем сопоставляет его N раз
      • Использование Lookahead для захвата означает, что повторение может быть N вместо N-1
    • .*? позволяет инфиксу разделять два прогона, не желая делать его как можно более коротким
    • (?=(?!\1)(.))\2{M}
      • аналогично первой части
      • Вложенный отрицательный прогноз гарантирует, что \1! = \2

Регулярное выражение запуска будет соответствовать более длинным циклам, например run(2,2) совпадений "xxxyyy":

xxxyyy <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{2}
  match
    0: [xxxyy]
    1: [x]
    2: [y]

Кроме того, он не позволяет перекрывать совпадения. То есть есть только один run(2,3) в "xx11yyy222".

xx11yyy222 <- (?=(.))\1{2}.*?(?=(?!\1)(.))\2{3}
  match
    0: [xx11yyy]
    1: [x]
    2: [y]
1 голос
/ 18 мая 2010

Предполагается, что вы используете perl / PCRE:

  1. (.{2})\1+ или ((.)(?!\2)(.))\1+. Второе регулярное выражение предотвращает сопоставление таких вещей, как oooo.

UPD : Тогда 2. будет ((.)\2{N}).*?((?!\2)(.)\4{M}). Удалите (?!\2), если хотите получить совпадения, например oooaoooo, и замените N и M на n-1 и m-1.

0 голосов
/ 18 мая 2010

Примеры в javascript

a = "This is my foobababababaf string"

console.log(a.replace(/(.)(.)(\1\2)+/, "<<$&>>"))

a = "This is my foobaafoobaaaooo string"

console.log(a.replace(/(.)\1+(.)\2+/, "<<$&>>"))
0 голосов
/ 18 мая 2010

Ну, это работает для первого ...

((.)(.))(\2\3)+
...