さて、前回までの記事で、クラスを使用すると既存のコードに手を入れずに機能追加しやすいことを見てきました。
その続きです。
まずは、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パスのマッチ部分の取得
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パスマッチ
その続きです。
まずは、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パスマッチ