让我们寻找 n=4 行,d 的 lookahead 断言得到满足,并且第一个 d 被正则表达式匹配。但是剩余的 d 没有被匹配,因为它们前面没有 3 个以上的 d。很明显,没有正则表达式,这是一个非常简单的字符串操作问题。我正在尝试只使用正则表达式来解决这个问题。
与任何正则表达式实现一样,答案取决于正则表达式的风格。你可以使用
.net 正则表达式引擎创建一个解决方案,因为它允许可变宽度的 lookbehinds。
此外,我将在下面提供一个更通用的解决方案,适用于 perl 兼容/类似的正则表达式风格。
.net解决方案
正如@PetSerAl在他的答案中所指出的那样,使用可变宽度的前后断言,我们可以断言回到字符串的开头,并检查是否有n个出现。
ideone演示
Python中的regex模块
您可以在python中实现此解决方案,使用Matthew Barnett的regex模块
,该模块还允许使用可变宽度的前后断言。
>>> 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”的变体中,没有一种解决方案可以实际返回每个重复字符的匹配,但我们可以为每个字符创建一个且仅一个捕获。
策略
对于任何给定的n,逻辑涉及:
- 早期匹配:匹配并捕获后面至少出现n次的每个字符。
- 最终捕获:
- 匹配并捕获一个字符,后面紧跟着恰好出现n-1次,以及
- 也捕获以下每个出现。
示例
for n = 3
input = abcdbcdcdd
字符c仅匹配一次(作为最终匹配),接下来的2次出现也在同一匹配中
捕获。
abcdbcdcdd
M C C
并且字符d
在 (早期) 匹配时仅匹配一次:
abcdbcdcdd
M
最后,匹配成功,并捕获了剩余的部分:
abcdbcdcdd
M CC
正则表达式
/(\w)
(?:
(?=(?:.*?\1){≪N≫})
|
(?=
(?:(?!\1).)*(\1)
(?:(?!\1).)*(\1)
≪repeat previous≫
(?!.*?\1)
)
)/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 = "";
for (N = 2; N <= 4; N++) {
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;
while ((match = re.exec(str)) !== null) {
output += "\nPos: " + match.index + "\tMatch:";
x = 1;
while (match[x] != null) {
output += " " + match[x];
x++;
}
}
output += "</pre>";
}
document.write(output);
Python3 代码
根据 OP 的要求,我链接到一个ideone.com 上的 Python3 实现