Ответ 1
ищите n = 4 строки, d lookahead assertion выполнено и сначала d соответствует регулярному выражению. Но оставшиеся d не сопоставляются, потому что у них нет еще 3 перед ними.
И, очевидно, без регулярного выражения это очень простая манипуляция строк проблема. Я пытаюсь сделать это с помощью только регулярного выражения.
Как и при любой реализации регулярного выражения, ответ зависит от аромата регулярного выражения. Вы можете создать решение с .net regex engine, потому что он позволяет изменять ширину.
Кроме того, я представлю более обобщенное решение ниже для perl-совместимых/подобных ароматов regex.
.net Решение
Как @PetSerAl указал в своем ответе, с переменной шириной lookbehinds, мы можем вернуться к началу строки и проверить, есть ли n.
демонстрация ideone
модуль regex в Python
Вы можете реализовать это решение в python, используя regex module
от Мэтью Барнетта, который также позволяет искать переменные ширины.
>>> import regex
>>> regex.findall( r'(\w)(?<=(?=(?>.*?\1){2})\A.*)', 'abcdbcdcdd')
['b', 'c', 'd', 'b', 'c', 'd', 'c', 'd', 'd']
>>> regex.findall( r'(\w)(?<=(?=(?>.*?\1){3})\A.*)', 'abcdbcdcdd')
['c', 'd', 'c', 'd', 'c', 'd', 'd']
>>> regex.findall( r'(\w)(?<=(?=(?>.*?\1){4})\A.*)', 'abcdbcdcdd')
['d', 'd', 'd', 'd']
>>> regex.findall( r'(\w)(?<=(?=(?>.*?\1){5})\A.*)', 'abcdbcdcdd')
[]
Обобщенное решение
В pcre или любой из "perl-like", нет решения, которое фактически возвращало бы соответствие для каждого повторяющегося символа, но мы могли бы создать один и только один захват для каждого символа.
Стратегия
Для любого заданного n логика включает в себя:
- Ранние совпадения: Сопоставление и захват каждого символа, за которым следует, по крайней мере, n больше случаев.
- Окончательные снимки:
- Сопоставьте и зафиксируйте символ, за которым следуют в точности n-1, и
- также фиксирует каждое из следующих случаев.
Пример
for n = 3
input = abcdbcdcdd
Символ c
имеет значение M, только один раз (как окончательный), а также следующие 2 вхождения также C, найденные в одном и том же совпадении:
abcdbcdcdd
M C C
а символ d
(ранний) M ашот один раз:
abcdbcdcdd
M
и (наконец) M еще раз, C удаляет остальные:
abcdbcdcdd
M CC
Regex
/(\w) # match 1 character
(?:
(?=(?:.*?\1){≪N≫}) # [1] followed by other ≪N≫ occurrences
| # OR
(?= # [2] followed by:
(?:(?!\1).)*(\1) # 2nd occurence <captured>
(?:(?!\1).)*(\1) # 3rd occurence <captured>
≪repeat previous≫ # repeat subpattern (n-1) times
# *exactly (n-1) times*
(?!.*?\1) # not followed by another occurence
)
)/xg
Для n =
-
/(\w)(?:(?=(?:.*?\1){2})|(?=(?:(?!\1).)*(\1)(?!.*?\1)))/g
демонстрация -
/(\w)(?:(?=(?:.*?\1){3})|(?=(?:(?!\1).)*(\1)(?:(?!\1).)*(\1)(?!.*?\1)))/g
демонстрация -
/(\w)(?:(?=(?:.*?\1){4})|(?=(?:(?!\1).)*(\1)(?:(?!\1).)*(\1)(?:(?!\1).)*(\1)(?!.*?\1)))/g
демонстрация - ... и т.д.
Псевдокод для генерации шаблона
// Variables: N (int)
character = "(\w)"
early_match = "(?=(?:.*?\1){" + N + "})"
final_match = "(?="
for i = 1; i < N; i++
final_match += "(?:(?!\1).)*(\1)"
final_match += "(?!.*?\1))"
pattern = character + "(?:" + early_match + "|" + final_match + ")"
Код JavaScript
Я покажу реализацию с использованием javascript, потому что мы можем проверить результат здесь (и если он работает в javascript, он работает в любом perl-совместимом регулярном выражении, включая .net, java, python, ruby, perl и все языки, на которых реализовано pcre, среди прочих).
var str = 'abcdbcdcdd';
var pattern, re, match, N, i;
var output = "";
// We'll show the results for N = 2, 3 and 4
for (N = 2; N <= 4; N++) {
// Generate pattern
pattern = "(\\w)(?:(?=(?:.*?\\1){" + N + "})|(?=";
for (i = 1; i < N; i++) {
pattern += "(?:(?!\\1).)*(\\1)";
}
pattern += "(?!.*?\\1)))";
re = new RegExp(pattern, "g");
output += "<h3>N = " + N + "</h3><pre>Pattern: " + pattern + "\nText: " + str;
// Loop all matches
while ((match = re.exec(str)) !== null) {
output += "\nPos: " + match.index + "\tMatch:";
// Loop all captures
x = 1;
while (match[x] != null) {
output += " " + match[x];
x++;
}
}
output += "</pre>";
}
document.write(output);