Я отчаянно ищу регулярные выражения, которые соответствуют этим сценариям:
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+/, "<<$&>>"))