さて、前回までの記事で、クラスを使用すると既存のコードに手を入れずに機能追加しやすいことを見てきました。
その続きです。

まずは、Antパスというのはご存知でしょうか?

聞き覚えがない方は先に以下をお読みください。


【Antパスとは】
Apache Antでよく使われるファイルのパスを記述する記法です。
例:
 ①/abc/*/sample.txt
 ②/abc/**.txt

ワイルドカードと同じ感じですが、*と**というワイルドカードが存在します。
*の場合は、/(スラッシュ)を含めません。
**の場合は、すべての文字がマッチします。

ですので上記の例では、①でマッチするパスは例えば以下のものになります。
 ・/abc/12/sample.txt
 ・/abc/ggg/sample.txt

①でマッチしないパスは例えば以下のものになります。
 ・/abc/12/12/sample.txt
 ・/abc/sample.txt

**では上記の例では全てマッチします。
しかし、/abc/sample.xmlや、/z/sample.txtのようなパスにはマッチしません。


なんとなくどんなものかわかりましたでしょうか?



【ロジック】
実装の仕方は簡単です。
ワイルドカードの*のクラスでスラッシュ(/)をマッチから除外すればよいだけです。
つまり、パースするときに以下のようにすれば良いだけです。

・* ⇒アスタリスクの検索クラスでスラッシュを除外して設定する
・** ⇒アスタリスクの検索クラスをそのまま使用する
・? ⇒?検索クラスをそのまま使用する

さて、上記でうまくいきそうですね!
では早速いってみましょう!!


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


//-----------------------------------------------------------
//Antパス除外文字を作る
const MCharVector createAntPathExcludeVec(){
MCharVector vec;
vec.push_back(FixedMChar("/"));
return vec;
};

//除外する文字(スラッシュ)
MCharVector antPathExcludeVec(createAntPathExcludeVec());

///Antパスマッチのパース関数の宣言
WildSearchAPtr parseAntPath(const char* pattern, const CharSet* charSet,
WildSearchAPtr end =WildSearchAPtr(new TerminatorSearch()), const int& num=1);


///Antパスマッチのパース関数実体
WildSearchAPtr parseAntPath(const char* pattern, const CharSet* charSet,
WildSearchAPtr end, const int& num){
int size = strlen(pattern);
MChar m = findWildMark(pattern, charSet);
WildSearchAPtr ret = end;

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

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

return ret;
};


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

//パース
WildSearchAPtr retAPtr = parseAntPath("/user/*/update/**.cgi", getCharSet("sjis"));
scoped_ptr<WildSearch> pattern(retAPtr.release());

cout << "Antパスのマッチ部分の取得" << endl;

//テスト
const char* str = "/user/00001/update/sell/abc.cgi";
SearchPointer p(str, getCharSet("sjis"), &callback);

//検索
cout << "dose it match?: " << (pattern->search(p) ? "true":"false") << endl;

//
cout << "search for " << str << endl;
cout << "1st match string is: " << callback.resultMap()[1] << endl;
cout << "2nd match string is: " << callback.resultMap()[2] << endl;

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



【出力】
Antパスのマッチ部分の取得
dose it match?: true
search for /user/00001/update/sell/abc.cgi
1st match string is: 00001
2nd match string is: sell/abc
続行するには何かキーを押してください . . .


【説明】
ちゃんとマッチ判定ができてますね!

しかも、マッチした部分の文字列の取得までできています!!


おもしろいですよね。
今回作ったのはAntパスのパース部分だけですが、Antパスマッチが実装できています。
こんなに簡単に実装できるのは、既存のクラスのおかげですにひひ

クラスって最高合格



【その他】
最後に、クラスによる実装の性能面についても見ておきましょう。
実は良いことばかりではありませんあせる
クラスを継承しているので少し遅くなります。

しかし、メンテ性や拡張性を考えると、少しくらい遅くてもメリットの方が大きいです。
速度がクリティカルな機能はC言語で作って、それほどクリティカルでない機能はクラスを
使用するなど、うまく使用していくと良いと思います。


さて、シリーズで長い記事を読んでいただいた方、とってもありがたいです。
楽しんでいただけたら嬉しいですニコニコ


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

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

ちなみに、C言語でAntパスマッチを書くと以下のようになります。
クラスとの比較も記述してみましたので、お時間あればお読みください。
 ・C言語でAntパスマッチ