C/C++
boost::xpressive 静的正規表現で書いてみた
VS2008以後は削除されてしまったCAtlRegExpのかわりにwindowsアプリの時はboost::xpressiveを使ってきましたが、はじめて静的正規表現を使ってみました。また、xpressiveはマルチバイト文字列非対応なんで_Unicodeプリプロセッサ付きです。(普段は国際化なんて意識していないのでTCHAR.h系の関数に慣れてなくて結構イライラしました...)
boost::xpressiveのイテレータ型の対応は、boost.Xpressive(日本語訳)(すばらしい!感謝)にあります。
| string::const_iterator | char* const | wstring::const_iterator | wchar_t* const | |
|---|---|---|---|---|
| basic_regex<> | sregex | cregex | wsregex | wcregex |
| match_results<> | smatch | cmatch | wsmatch | wcmatch |
| regex_compiler<> | sregex_compiler | cregex_compiler | wsregex_compiler | wcregex_compiler |
| regex_iterator<> | sregex_iterator | cregex_iterator | wsregex_iterator | wcregex_iterator |
| regex_token_iterator<> | sregex_token_iterator | cregex_token_iterator | wsregex_token_iterator | wcregex_token_iterato |
今回はワイド文字列対応なんで、wsregexとwsmatchを使います。先にも書きましたがこれまでは(仕様さえ決まってしまえば)特に動的である必要はないのに動的正規表現を使っていた怠慢を反省し静的正規表現で書いてみました。とりあえず、現状決まっているのは、文字列を「最後の空白」空白がなければ、「最初の数字」で区切るです。
pair<wstring,wstring> split_wstr(const wstring& wstr)
{
boost::xpressive::wsmatch matched;
//最後の空白で分割
#ifdef _DYNAMIC_REGEX_
boost::xpressive::wsregex regex_lastw =
boost::xpressive::wsregex::compile(_T("^(\\S.+)\\s(.+)$"));
#else
boost::xpressive::wsregex regex_lastw =
bos >> (s1=~_s >> +_) >> _s >> (s2=+_) >> eos;
#endif
if (boost::xpressive::regex_match(zname,matched,regex_lastw))
{
return pair<wstring,wstring>(matched.str(1),matched.str(2));
}
//最初の数字で分割
#ifdef _DYNAMIC_REGEX_
boost::xpressive::wsregex regex_firstn =
boost::xpressive::wsregex::compile(_T("^(\\D+)(\\d.+)$"));
#else
boost::xpressive::wsregex regex_firstn =
bos >> (s1=+~_d) >> (s2=_d >> +_) >> eos;
#endif
if (boost::xpressive::regex_match(zname,matched,regex_firstn))
{
return pair<wstring,wstring>(matched.str(1),matched.str(2));
}
// 以下仕様に応じていろんな分割が続く
:
}ご覧の通り、普段perlやrubyなんかで正規表現書いている人にとっては一見わかりにくいのが弱点でしょうか?特にドットをアンダースコアにするとか*や+が前に来るなどなかなか習慣からは抜け出せないと思うので、コメントとデバグの意味を込めて動的正規表現も併記したほうが後々のためかもしれません。
C++のtemplateはやっぱすごいや
「プログラミング原論」第三章のお題でフォボナッチ数列をやったんですけど、Project Eulerでもやったなぁって思い出して探してみたらProblem25で使ってました。そのとき書いたのが、
fib :: [Integer]
fib = 0:1:(zipWith (+) fib (tail fib))たったの2行のコレ。
前回のエントリで、うんうん言いながらC++をHaskellで書き直したpower_fib_accumulateとかpower_fibって何だったの?ってくらいのシンプルさ。Haskellのウリのひとつに"簡潔な実装が可能"っていうのよく見かけますけどホントですね。
その一方で、C++で書いたpower_accumulateとかpowerなんてのは汎用でこの章でやったようにオペランドの型を選びません。intだろうがpairだろうがpower_accumulateやpowerを使うことができます。Haskellでは(先のコードのように2行で済むなら最初からpower_accumulateやpowerを書き直してまで使う必要はないんですが)タプルの二項演算を受け付けるように書き直す必要がありました。厳密な型がじゃまをします。
どちらがどうと言うことはないんですが、第三章までをとおしてC++のテンプレートの強力さを見せつけられ(まぁ、著者がAlexander Stepnovですから...)改めてC++(with STL,Boost,Loki...)ってスゲーなって思い知らされました。
一番長いこと触れている言語だけどこのところHaskellばかり勉強していて疎遠になっているのでC++で書く仕事でも探してみるかというちょっとシアワセな気分。
boost::gregorian::dateの月(数値)の取得
boost::gregorian::dateでdateObj.month()すると、Nov
とかDec
とかが返ってくる。dateObj.month().as_number()がデフォルトのほうが僕はいいと思う。月を取得して文字列が返るのは直感的では内容に思うのですが。いや、ハマったから言うのじゃありません...
それにしても、boost::gregorianは重いですね。Regexなんかと併用するとプリコンパイルのメモリが足りないとか言って(VS2008)きて/zmするハメになります。こうなると大抵Intellisenseが壊れるのでまあ、今回のようにヘッダを読む羽目になるわけです。windowsアプリの場合、無理して使わないようにしようかと思います。
strncpy_s()への修正で考えさせられた件
vs2005からCRTセキュリティ強化ということで*_s()系の関数が導入されています。でもこれ、よく考えないで修正すると痛い目にあいそう。僕の場合、既存の次のようなコードで躓きました。
typedef struct _dest { char x[3]; char y[5]; char z[5] } dest;ような構造体にデータを読み込み、x,y,zのそれぞれを整数に変換する下記のような処理があったのですが、
ようやくVisualStudio2005
ずっと稟議をだしていてようやく通ったVisualStudio 2005。いいぇ、2005ですとも。ここまで引っ張られたらいっそのこと2008でもヨカッタかと...早速、アプリの移行を開始したのですがいろいろあります。まず、セキュリティ強化なんたらで文句言われちゃって、警告の山。最初は律儀にセキュリティ強化版の関数XXX_s()に置き換えたんだけれど、なんか馬鹿馬鹿しくなってヤメ。
DB2 ODBC経由で接続してみる
またDB2ネタ(このところ、毎日触ってるもので...)。C/C++でプログラミングする場合、前回書いたようなSQL埋め込み型だとコードが冗長になるのでODBC経由での実装するにはどうしたらいいかと思って、あれこれサンプルを漁っていたら、昨日インストールしたruby用DB2ドライバ(ibm_db2.c)がまさにソレでした。ソースをチェックしてみたらconnect時にSQLSetEnvAttr()という関数でSQL_ATTR_ODBC_VERSION,SQL_OV_ODBC3を指定していました。






最近のコメント
34 weeks 2 days ago
51 weeks 2 days ago
51 weeks 2 days ago
1年 16 weeks ago
1年 16 weeks ago
1年 16 weeks ago
1年 28 weeks ago
1年 28 weeks ago
2 years 8 weeks ago
2 years 17 weeks ago