Требуется регулярное выражение для соответствия специальным ситуациям

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

1) Совместить чередующиеся символы

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

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

Я действительно не знаю, с чего начать 🙁

2) Сопоставьте комбинированные группы

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

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

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

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

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

"xxxyyy" выражение run будет соответствовать более длинным тиражам, например run(2,2) соответствует "xxxyyy" :

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

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

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

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

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

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

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

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

Примеры в 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+/, "<<$&>>"))