「部分一致??何を言ってるの??」

と思われた方、いらっしゃいますよね?
まずは、部分一致のワイルドカード検索って何を指しているのか、から行きましょうか。



【部分一致のワイルドカードとは】
通常、ワイルドカードマッチというと、
例えば、"ab12345c12"が"ab*c"にマッチするか?を調べます。
このとき、文字の先頭から終端までがマッチするかを調べますので、この例ではマッチしません。

しかし、よく見ると一部はマッチしそうです。
つまり、先頭の"ab12345c"の部分ですビックリマーク

これが部分一致のワイルドカードです。

別に先頭からマッチしなくても良いです。
"11ab123c11"などでも部分的にはマッチします。

このような検索を作ってみましょう。

ただし、以前の記事のコードを流用し、以前の記事のコードに一切手を入れません。




【前座】
部分一致させるにはクラスが足りませんので派生クラスを追加します。
終了を文字列の終端でなくてもマッチさせるワイルド検索クラスです。
先頭からマッチしなくても良いので、最初のマッチ位置も検索できないといけませんが
その検索は*の検索クラスを使用します。
部分一致の検索は、ちょうど、完全一致のワイルドカード検索で先頭に*をつけて検索するのと同じですね。先ほどの"ab*c"の例では、"*ab*c"ですね。

でもそうすると"*ab*c*"で検索しても同じではないとかと思われるかもしれません。
しかし、そうすると処理速度が遅くなります。
*の検索クラスは、1文字ずつずらして終端とマッチするかチェックしていくからです。
ですので今回はすぐに検索を終了する検索クラスを追加することにしました。


【サンプル】
前回の記事のmain関数ごと以下のコードで置き換えてください。
(前回の記事は2つの記事のマージになっていますが、マージされたものを置き換えて下さい)


//---------------------------------------------------


/**
終わり 。文字列に無関係に検索を終了する。
*/
class FinishSearch : public WildSearch{
public:
enum{NUM=-1, KIND=6};

///
FinishSearch()
: WildSearch(NUM, NULL, KIND) {};

///いつでもtrueを返す
virtual const bool search(SearchPointer& p) const {
p.callback->send(this->num(), p.curPos, 0);
return true;
};
};


//パース関数-------------------------------------
//部分一致ワイルドカードのパース
WildSearchAPtr parsePartialWildCard(const char* pattern, const CharSet* charSet){
WildSearchAPtr ret(new FinishSearch());
ret = parseWildCard(pattern, charSet, ret, MCharVector(), 1);
return WildSearchAPtr(new AstaSearch(0, ret.release(), MCharVector()));
};


//------------------------------------
int main(int argc, char *argv[]) {
MCharVector excludeVec;

//パース
WildSearchAPtr retAPtr = parsePartialWildCard("ab*c", getCharSet("sjis"));
scoped_ptr<WildSearch> pattern(retAPtr.release());

cout << "パースによる部分一致ワイルドカード検索" << endl;

//テスト
search(pattern, "abc");
search(pattern, "abdddc");
search(pattern, "ac");
search(pattern, "abcd");

system("PAUSE");
return EXIT_SUCCESS;
};




【出力】
パースによる部分一致ワイルドカード検索
pattern: abc, true
pattern: abdddc, true
pattern: ac, false
pattern: abcd, true
続行するには何かキーを押してください . . .


【説明】
前回と結果が変わってますね。
前回は、"abcd"は"ab*c"とマッチしませんでしたよねビックリマーク


単純にクラスを追加してパース関数を用意しただけです。
このパース関数も、前回の完全一致のパース関数を流用してコード量が少なくなっています。

既存のクラスや既存の関数には手を入れていません。

クラスを使用しないサンプルではこうは行きませんよねえっ
クラスを使う面白さが伝わるとうれしいのですが・・・にひひ


【その他の関連記事】
このワイルド検索の記事はシリーズになっていて、順を追ってみてもらえればと思います。

 ・ワイルドカード検索をする
 ・WildSearchを"ac*c"などの文字列から自動で作成する
 ・部分一致のワイルドカード検索をする
 ・*や?にマッチした文字列をコールバックを使用して取得する
 ・Antパスマッチを実装する
 ・おまけ:ワイルドカード検索すべてのコードをまとめたもの