次のコードは、実際の表現を変更することなく、任意の正規表現で機能するはずです。
Regex rx = new Regex("(a)\1"); // or any other word you're looking for.
int position = 0;
string text = "aaaaabbbbccccaaa";
int textLength = text.Length;
Match m = rx.Match(text, position);
while (m != null && m.Success)
{
Console.WriteLine(m.Index);
if (m.Index <= textLength)
{
m = rx.Match(text, m.Index + 1);
}
else
{
m = null;
}
}
Console.ReadKey();
オプションを使用して、連続する検索ごとに正規表現検索の開始インデックスを変更します。実際の問題は、正規表現エンジンがデフォルトで、前の一致の後も常に検索を続行するという事実から生じます。そのため、先読み構造を使用するか、開始インデックスを手動で設定することによって指示しない限り、別の一致内で可能な一致を見つけることはありません。
もう 1 つの比較的簡単な解決策は、式全体を先読みすることです。
string expression = "(a)\1"
Regex rx2 = new Regex("(?=" + expression + ")");
MatchCollection ms = rx2.Matches(text);
var indexes = ms.Cast<Match>().Select(match => match.Index);
こうすることで、エンジンは一致が見つかるたびに自動的にインデックスを 1 つ進めます。
ドキュメントから:
NextMatch メソッドを呼び出して一致の試行が繰り返されると、正規表現エンジンは空の一致を特別に処理します。通常、NextMatch は、前の一致が中断したところから次の一致の検索を開始します。ただし、空の一致の後、NextMatch メソッドは次の一致を試行する前に 1 文字進みます。この動作により、正規表現エンジンが文字列を処理することが保証されます。そうしないと、空の一致では前方への移動が発生しないため、次の一致は前の一致とまったく同じ場所から開始され、同じ空の文字列に繰り返し一致します。