前回の記事では、クラスを使用したワイルドカード検索のサンプルを見ました。
しかし、"ab*c"のような検索文字列もクラスで作らないといけませんでした。

ここでは、ワイルドカードクラスを自動で作るサンプルを作ってみましょう!!



【サンプル】
前回の記事のmain関数ごと以下のコードで置き換えてください。


//パース----------------------------------------------
typedef auto_ptr<WildSearch> WildSearchAPtr;

//ワイルドカード文字を作る
const MCharVector createMCharVectorWildMark(){
MCharVector vec;
vec.push_back(FixedMChar("*"));
vec.push_back(FixedMChar("?"));
return vec;
};

//ワイルドカード文字*?
MCharVector markVec(createMCharVectorWildMark());

//*?いづれかを検索する
MChar findWildMark(const char* pattern, const CharSet* charSet){
CharMCharIterator i = mcharIterator(pattern, charSet);
CharMCharIterator end = mcharIterator(pattern + strlen(pattern), charSet);
return *find_first_of(i, end, markVec.begin(), markVec.end());
};


/**
<pre>
ワイルドカードマッチ WildSearch を作成する。
マッチの検索開始位置は文字の先頭 。

【num(番号)について】
WildSearch クラスのnum(番号)の開始の数値。
例えば、patternが"ab*c*d"で、num=1 の場合、 b*cの部分の*は"1"が設定され、
c*dの部分の*は"2"が設定される。これらの数値はコールバックに数値が渡される。
*,?以外を表す WildSearch クラスは固定で番号が設定される。
*,?以外の WildSearch クラス番号は各クラスのNUMで参照する。 
例: TerminatorSearch::NUM

【作成された検索を使用したときの例】
a*bの場合:(end= TerminatorSearch のとき)
  ab ⇒マッチする
  akb ⇒マッチする
  kakb ⇒マッチしない
  akbn ⇒マッチしない
</pre>
@param pattern [in]パースする検索パターン(例:"ab*c")
@param charSet [in]文字コード
@param end [in]最後に追加する検索
@param exclude [in]ワイルドカード(*,?)でマッチさせたくない文字。
@param num [in]コールバックのマッチ開始位置。
*/
WildSearchAPtr parseWildCard(const char* pattern, const CharSet* charSet,
WildSearchAPtr end, const MCharVector& exclude, const int& num){
int size = strlen(pattern);
MChar m = findWildMark(pattern, charSet);
WildSearchAPtr ret = end;

//*?が見つかった場合
if(m.pos() < pattern + size){
if(*m.pos() == '*'){
//*を作る
ret = parseWildCard(m.pos() + 1, charSet, ret, exclude, num + 1);
ret.reset(new AstaSearch(num, ret.release(), exclude));
}else{
//?を作る
ret = parseWildCard(m.pos() + 1, charSet, ret, exclude, num + 1);
ret.reset(new QuestionSearch(num, ret.release(), exclude));
}
}

//文字列の部分を作る
int len = m.pos() - pattern;
if(len > 0){
ret.reset(new OnlyStrSearch(OnlyStrSearch::NUM, string(pattern, len), ret.release()));
}

return ret;
};


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

//パース
WildSearchAPtr retAPtr = parseWildCard("ab*c", getCharSet("sjis"),
WildSearchAPtr(new TerminatorSearch()), excludeVec, 1);
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, false
続行するには何かキーを押してください . . .


【説明】
出力は当然ながら前回と同じですニコニコ

今回のようにワイルドカード文字列"ab*c"を分解するのをパースするなどと言ったりします。
パースはそれほど難しくありません。
再起呼び出しを使用して作成したWildSeachクラスを溜めていくだけです。

 <findWildMark関数について>
 *か?のいづれかが最初に見つかった位置を教える関数です。
 今回は、この関数を利用して、
 "ab*c"のような文字を、"ab","*","c"のように分解しながら再起呼び出しをさせました。


割と簡単にできることが分かるかと思います。



【まとめと次の記事へのフリ】
見ていただいたように、ワイルドカードクラス(WildSearch)のようなクラスさえ作ってしまえば、
あとはパースを作るだけで簡単に処理を実装できます。
これはワイルドカードに限らないと思います。

クラスをうまく使用すると今回見たように既存のソースを触らずに機能追加ができます。

この次は、さらに既存のコードを変更せずに部分一致するワイルドカードマッチを
作ってみますにひひ


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

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