boost_regexの正規表現

C++正規表現を使う必要が出てきたのでboost::regex_merge()に関して調べている。
なんでregex_replace()じゃなくて"duplicated"なregex_merge()なのか?
開発環境のboostのバージョンが1.30.2なんだからしょうがないのです。

1.30.xはもうドキュメントにも記載されていないっぽい。(regex_merge()の使い方は載っているみたいだ)
このサンプルコードではC++ソースコードを簡単なシンタックスハイライトで色づけした結果をファイル出力するようだ。(vimなどもこうゆうライブラリを使ってシンタックスハイライトを実現しているのだろうか)

このソースコードを読んでいて不思議に思った正規表現はこれ。

(?1正規表現)

こんな正規表現あったかなと思ってboostのドキュメントを調べたところ、ここのConditionalsになにやら書いてあった。

どうやらboost_regex独自の構文らしく1.30.2だとこの2つが使えるみたいだ。

(?N) true-expression   --> N番目の()の条件にマッチした場合置換される
(?:) false-expression  --> N番目の()意外の条件にマッチした場合置換される


例をあげるとこんな使い方ができる。

"(while)|(for)|(if)" // 正規表現

"(?1WHILE:OTHER)"    // 置換後のフォーマット

"while for if"       // 与えるデータ

この条件でregex_merge()をかけると以下のようになる
"WHILE OTHER OTHER" // 置換後のデータ

正直なところfalse-expressionの賢い使い方が思いつかない。


はてな記法の一部をregex_mergeで実装するとこんな感じになるのかな。
※20081109追記 このサンプルコードはregex_repraceですがregex_mergeでも動きました。

#include <string>
#include <sstream>
#include <iterator>
#include <fstream>
#include <iostream>
#include <boost/regex.hpp>

const char* EXPRESSION_TEXT =
     "\\[google:([^]]+)\\]|"
     "\\[(s?https?://[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+)\\:title=([^]]+)\\]|"
     "mailto\\:(([a-zA-Z0-9])+([a-zA-Z0-9._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9._-]+)+)" // メールアドレスの正規表現は手抜きです
    ;

const char* FORMAT_STRING =
     "(?1<a href=\"http\\://www.google.com/search?q=$1&ie=utf-8&oe=utf-8\" target=\"_blank\">$1</a>)"
     "(?2<a href=\"$2\" target=\"_blank\">$3</a>)"
     "(?4<a href=\"mailto\\:$4\">$4</a>)"
    ;

const std::string INPUT_STRING =
    "[google:はてな]\n"
    "[http://www.hatena.ne.jp/:title=はてなのトップページ]\n"
    "mailto:info@hatena.ne.jp\n"
    ;

int main(int argc, const char** argv) {
    try {
        boost::regex e1;
        e1.assign(EXPRESSION_TEXT);
        std::cout << "before\n" << INPUT_STRING << std::endl;

        std::ostringstream oss(std::ios::out | std::ios::binary);
        std::ostream_iterator<char, char> os_it(oss);
        boost::regex_replace(os_it,
                             INPUT_STRING.begin(),
                             INPUT_STRING.end(),
                             e1,
                             FORMAT_STRING,
                             boost::match_default | boost::format_all);

        std::cout << "\nafter\n" << oss.str() << std::endl;
    }
    catch (...)
    {
        std::cerr << "failed regex_replace()" << std::endl;
        return -1;
    }

    return 0;
}