Я отчаянно ищу регулярные выражения, которые соответствуют этим сценариям:
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
\1 ! = \2 \0 иметь полное соответствие (а не только конец «хвоста») (?:\1\2){2,} фиксирует последовательность \1\2 , которая должна повторяться как минимум дважды. (?=(.))\1{N}.*?(?=(?!\1)(.))\2{M} имеет три части
(?=(.))\1{N} захватывает \1 в lookahead, а затем соответствует N раз
N вместо N-1 .*? позволяет инфикс отделить два пробега, не желая держать его как можно короче (?=(?!\1)(.))\2{M}
\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:
(.{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+/, "<<$&>>"))