バックグラウンド。 大きな文字列内の特定のテキストを繰り返し検索しているときに、スクリプトでStackOverflowExceptionが発生しました。ループは無限ではありません。問題は(特定の検索で)9,000〜10,000の正当な検索で発生します-続行するには問題が必要です。私は末尾再帰を使用しています(私は思います)。C#ではこれがうまくいかないことがわかったので、それが私の問題の一部である可能性があります。ただし、私の場合、末尾再帰の使用を回避する方法がわかりません。
質問。StackOverflowExceptionが発生するのはなぜですか?私の全体的なアプローチは理にかなっていますか?デザインがうまくいかない場合は、例外を回避するだけでなく、そこから始めたいと思います。しかし、設計が受け入れられる場合、StackOverflowExceptionについて何ができますか?
コード。 私が書いたクラスは、大量のテキスト(約6MB)で連絡先(指定されたリストから約500以上)を検索します。私が使用している戦略は、名前を検索してから、名前の直前または直後のどこかで名前を探すことです。与えられたテキスト内の各連絡先の各インスタンスを見つける必要があります。StringSearcherクラスには、連絡先の検索を続行する再帰メソッドがあり、連絡先が見つかるたびに結果を返しますが、検索を中断した場所を追跡します。
私はこのクラスを次のように使用します。
StringSearcher searcher = new StringSearcher(
File.ReadAllText(FilePath),
"lastname",
"firstname",
30
);
string searchResult = null;
while ((searchResult = searcher.NextInstance()) != null)
{
// do something with each searchResult
}
全体として、スクリプトは機能しているようです。ほとんどの連絡先は、私が期待する結果を返します。ただし、この問題は、プライマリ検索文字列が非常に一般的(数千ヒット)であり、セカンダリ検索文字列が発生しないか、ほとんど発生しない場合に発生するようです。CurrentIndexが正常に進んでいるので、スタックしていないことはわかっています。
これが私が話している再帰的な方法です。
public string NextInstance()
{
// Advance this.CurrentIndex to the next location of the primary search string
this.SearchForNext();
// Look a little before and after the primary search string
this.CurrentContext = this.GetContextAtCurrentIndex();
// Primary search string found?
if (this.AnotherInstanceFound)
{
// If there is a valid secondary search string, is that found near the
// primary search string? If not, look for the next instance of the primary
// search string
if (!string.IsNullOrEmpty(this.SecondarySearchString) &&
!this.IsSecondaryFoundInContext())
{
return this.NextInstance();
}
//
else
{
return this.CurrentContext;
}
}
// No more instances of the primary search string
else
{
return null;
}
}
StackOverflowExceptionはthis.CurrentIndex = ...
、次のメソッドで発生します。
private void SearchForNext()
{
// If we've already searched once,
// increment the current index before searching further.
if (0 != this.CurrentIndex)
{
this.CurrentIndex++;
this.NumberOfSearches++;
}
this.CurrentIndex = this.Source.IndexOf(
this.PrimarySearchString,
ValidIndex(this.CurrentIndex),
StringComparison.OrdinalIgnoreCase
);
this.AnotherInstanceFound = !(this.CurrentIndex >= 0) ? false : true;
}
必要に応じて、さらにコードを含めることができます。それらのメソッドまたは変数の1つに問題があるかどうかを教えてください。
*これはスケジュールされたタスクとして夜間に実行される可能性が高いため、パフォーマンスは実際には問題ではありません。