2011-02-05 7 views
28

Boyer-Mooreは、おそらく最も知られているインデックスなしのテキスト検索アルゴリズムです。だから、私はBlack Belt CoderウェブサイトのC#で実装しています。Boyer-Moore C#で実践していますか?

私はそれを動作させました。これは、String.IndexOf()と比較して、予想されるパフォーマンスの向上をほぼ示しました。しかし、StringComparison.Ordinal引数をIndexOfに追加すると、Boyer-Mooreの実装よりパフォーマンスが向上し始めました。時には、かなりの量。

なぜ誰かが私を助けることができるのだろうかと思います。私はなぜStringComparision.Ordinalが物事をスピードアップするのか理解していますが、Boyer-Mooreより速いのはどうでしょうか?それは.NETプラットフォーム自体のオーバーヘッドのためでしょうか。おそらく、配列インデックスが範囲内にあるかどうかを確認するために検証する必要があります。いくつかのアルゴリズムはC#.NETでは実用的ではありませんか?

以下はキーコードです。

// Base for search classes 
abstract class SearchBase 
{ 
    public const int InvalidIndex = -1; 
    protected string _pattern; 
    public SearchBase(string pattern) { _pattern = pattern; } 
    public abstract int Search(string text, int startIndex); 
    public int Search(string text) { return Search(text, 0); } 
} 

/// <summary> 
/// A simplified Boyer-Moore implementation. 
/// 
/// Note: Uses a single skip array, which uses more memory than needed and 
/// may not be large enough. Will be replaced with multi-stage table. 
/// </summary> 
class BoyerMoore2 : SearchBase 
{ 
    private byte[] _skipArray; 

    public BoyerMoore2(string pattern) 
     : base(pattern) 
    { 
     // TODO: To be replaced with multi-stage table 
     _skipArray = new byte[0x10000]; 

     for (int i = 0; i < _skipArray.Length; i++) 
      _skipArray[i] = (byte)_pattern.Length; 
     for (int i = 0; i < _pattern.Length - 1; i++) 
      _skipArray[_pattern[i]] = (byte)(_pattern.Length - i - 1); 
    } 

    public override int Search(string text, int startIndex) 
    { 
     int i = startIndex; 

     // Loop while there's still room for search term 
     while (i <= (text.Length - _pattern.Length)) 
     { 
      // Look if we have a match at this position 
      int j = _pattern.Length - 1; 
      while (j >= 0 && _pattern[j] == text[i + j]) 
       j--; 

      if (j < 0) 
      { 
       // Match found 
       return i; 
      } 

      // Advance to next comparision 
      i += Math.Max(_skipArray[text[i + j]] - _pattern.Length + 1 + j, 1); 
     } 
     // No match found 
     return InvalidIndex; 
    } 
} 

EDIT:私はhttp://www.blackbeltcoder.com/Articles/algorithms/fast-text-search-with-boyer-mooreで問題にすべての私のテストコードと結論を掲載しました。

+4

ジョナサン、 "C#.NET"のようなものはありません。 –

+0

内部的にBoyer-Mooreが.netに採用されている可能性を完全に排除していますか?ちょっと興味があるんだけど。 –

+0

http://stackoverflow.com/questions/2584169/what-algorithm-net-use-for-searching-a-pattern-in-a-stringおよび特に受け入れられた回答の下のコメントを参照してください。 –

答えて

19

私自身のテストとここでのコメントに基づいて、理由がStringComparision.Ordinalでうまくいくと結論づけました。なぜなら、このメソッドは手作業で最適化されたアセンブリ言語を採用するアンマネージコードを呼び出すからです。

私は多くの異なるテストを実行しました。String.IndexOf()は、マネージC#コードを使用して実装できるものより速いようです。

興味があれば、これについて私が発見したすべてを書き、Boyer-MooreアルゴリズムのいくつかのバリエーションをC#でhttp://www.blackbeltcoder.com/Articles/algorithms/fast-text-search-with-boyer-mooreに投稿しました。

+0

String.IndexOf(value、StringComparison.Ordinal)> = 0。String.Contains()が役に立ちそうな人には、String.Contains()を呼び出します。したがって、結論は文字列検索のためにString.Conatinst()を使用することです。 – ValidfroM

+0

この結論はデータに依存します。 Boyer Mooreは、適切なデータに対して任意に高速化することができます。 – usr

+0

@usr:場合によっては速いという証拠がある場合は、その証拠を自由に提示してください。私はBoyer-Mooreを徹底的に理解していて、特定のデータの方が速い方法を完全に理解していますが、さまざまなデータをテストして、String.IndexOf() –

4

私の考えでは、そのフラグを設定することで、String.IndexOfはBoyer-Moore自体を使用することができます。そしてその実装はあなたよりも優れています。

このフラグがないと、Unicodeに関する潜在的な問題のために、Boyer-Moore(注意してください)を使用することに注意する必要があります。特にUnicodeの可能性は、Boyer-Mooreが使用する遷移テーブルを爆破させる原因となります。

+0

私は、かなり標準的な実装を使用しているので、それはきちんとしたトリックです。しかし、管理されていないコードで実行すると、パフォーマンスが向上する可能性があります。 –

+2

BCLがBoyer-Moore検索を使用している場合は、検出可能である必要があります。長い文字列( "abcdefghijklmnopqrstuvwxyz")を検索すると、短い文字列( "a")を検索するよりも速くなるはずです。 – Gabe

+0

@Gabe:良い点ですが、そうではありません。何があっても速いようです。一方、私のBoyer-Mooreルーチンは、検索パターンの長さの影響を確実に受けます。 –

関連する問題