boost::regex を使って /~/g みたいなことをやる方法2007年06月04日 00時28分54秒

宿題をひとつ解きますた。

  1. Perl で言うところの /$pattern/g に相当する記述方法はないか?
    • boost::regex_grep() というのはあったらしいが、すでに deprecated 。Predicate とかいうコールバックらしきものの設定が必須な模様で、そういう意味でも使いにくい (Perl の grep 関数を意識してるのかな?)。
    • boost::regex コンストラクタで std::regex_constants::grep または std::regex_constants::egrep を指定した場合、どうなるか?
    • Perl の tr/.../.../ 相当の記述法も併せて検証する。ふつーに iterator 回せって? まぁそうなんだけどね。

boost::regex_iteratorboost::make_regex_iterator() を用いて生成する方法と、boost::basic_regex のコンストラクタに渡すパラメータ値 boost::regex_constants::egrep との併用でいけそうです (訂正: Tue Jun 5 22:22:23 JST 2007)。以下、サンプル。

#include <iostream>
#include <string>

#include <boost/regex.hpp>

using namespace std;
using boost::regex; using boost::smatch; using boost::sregex_iterator;
using boost::regex_constants::egrep;
using boost::make_regex_iterator;

int main()
{
    string text = "foo bar (baz) hoge (huga) o(yoy)o nan(to iu ko)toda-";

    for (sregex_iterator it = make_regex_iterator(text, regex("\\(([^\\)]+)\\)", egrep));
        it != sregex_iterator(); it++)
    {
        cout << (*it)[1] << endl;
    }
}

実行結果はこんな感じ。

C:\Program_1\vs8\regex_test_mb\debug>regex_test_mb.exe
baz
huga
yoy
to iu ko

C:\Program_1\vs8\regex_test_mb\debug>

Tue Jun 5 22:22:23 JST 2007 - 追記

boost::regex_constants::egrep は不要でした。

それから、一括置換を行いたい場合は、普通に boost::regex_replace() アルゴリズムを使えばいい模様です (逆に一括では置換したくない場合はどうすればいいんだ?)。boost::match_results::format() はあくまでマッチ結果を利用して Perl 風に置換のフォーマットを記述できるというただそれだけの代物のようです。

以下、総括的なサンプルソース。

#include <iostream>
#include <string>

#include <boost/regex.hpp>

using namespace std;
using boost::regex;
using boost::sregex_iterator;
using boost::make_regex_iterator;
using boost::regex_replace;

int main()
{
    string text = "foo bar (baz) hoge (huga) o(yoy)o nan(to iu ko)toda-";
    cout << text << endl;

    for (sregex_iterator it = make_regex_iterator(text, regex("\\(([^\\)]+)\\)"));
        it != sregex_iterator(); it++)
    {
        cout << (*it)[1] << endl;
        cout << it->format("[$1]") << endl;
    }

    cout << regex_replace(text, regex("\\(([^\\)]+)\\)"), "[$1]") << endl;
}

実行結果は以下のとおり。

C:\Program_1\vs8\regex_test_mb\debug>regex_test_mb.exe
foo bar (baz) hoge (huga) o(yoy)o nan(to iu ko)toda-
baz
[baz]
huga
[huga]
yoy
[yoy]
to iu ko
[to iu ko]
foo bar [baz] hoge [huga] o[yoy]o nan[to iu ko]toda-

C:\Program_1\vs8\regex_test_mb\debug>

Wed Jun 6 12:27:51 JST 2007 - 追記

s/~/eg みたいなことをやる方法もわかったので追記。よーするに regex_replace() アルゴリズムを自前でやっつける方法ですね。

その前に。まず、make_regex_iterator() は、regex_iterator のコンストラクタを呼べるのであれば、不要です。ていうか、効率を考えればむしろそうするべきです。make_regex_iterator() 自体は regex_iterator コンストラクタの単なる構文糖に過ぎません。

で、自前でテキスト置換を実装するにはマッチしなかった部分のフレーズが (適切なタイミングで) 得られる必要がありますが、それは match_results::prefix() で取得できます。また、マッチングのループで舐められることのなかった部分 (最後にマッチしたフレーズよりも後ろの部分) については、最後に評価された regex_iteratormatch_results::suffix() にて取得できます。

以上を踏まえた上で、サンプルソースを以下に示します。

#include <iostream>
#include <string>

#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>

using namespace std;
using boost::regex;
using boost::sregex_iterator;
using boost::make_regex_iterator;
using boost::regex_replace;
using boost::lexical_cast;

int main()
{
    string text = "foo bar (baz) hoge (huga) o(yoy)o nan(to iu ko)toda-";
    cout << text << endl;

    string modified;
    sregex_iterator last_it;
    for (sregex_iterator it(text.begin(), text.end(), regex("\\(([^\\)]+)\\)"));
        it != sregex_iterator(); it++)
    {
        modified += it->prefix() + it->format("[$1:") +
            lexical_cast<string>((*it)[1].str().length()) + "]";
        last_it = it;
    }
    modified += last_it == sregex_iterator() ? text : last_it->suffix();

    cout << modified << endl;
}

ひとつもマッチしなかった場合を考慮して、last_it をデフォルトコンストラクタにて生成される空イテレータと比較することを忘れてはいけません。

出力結果は以下のようになります。

C:\Program_1\vs8\regex_test_mb\debug>regex_test.exe
foo bar (baz) hoge (huga) o(yoy)o nan(to iu ko)toda-
foo bar [baz:3] hoge [huga:4] o[yoy:3]o nan[to iu ko:8]toda-

C:\Program_1\vs8\regex_test_mb\debug>

boost::regex を使って Perl の split みたいなことをやる方法2007年06月06日 15時34分02秒

次の宿題もやってみた。

  1. Perl の split 関数に相当する記述法はないか?
    • boost::regex_split も deprecated 。つかこいつも使い勝手が微妙くさいなぁ。。。回りくどいというか。

前回の解答match_results::prefix()match_results::suffix() を見つけた時点でもう解けたも同然ではあったのですが、念のため。以下、サンプル。

#include <iostream>
#include <string>
#include <vector>
#include <iterator>

#include <boost/regex.hpp>

using namespace std;
using boost::regex;
using boost::sregex_iterator;

back_insert_iterator<vector<string> >
split(const string& pattern,
      const string& source,
      back_insert_iterator<vector<string> > phrases_it)
{
    sregex_iterator last_it;
    for (sregex_iterator it(source.begin(), source.end(), regex(pattern));
        it != sregex_iterator(); it++)
    {
        *phrases_it++ = it->prefix();
        last_it = it;
    }
    *phrases_it++ = last_it == sregex_iterator() ? source : last_it->suffix();

    return phrases_it;
}

inline void split(const string& pattern, const string& source, vector<string>& phrases)
{
    split(pattern, source, back_insert_iterator<vector<string> >(phrases));
}

int main()
{
    string text = "  foo, bar,  baz, ,ngan gu  , hogehu,,ga-- ";
    cout << text << endl;

    vector<string> phrases;
    split("\\s*,\\s*", text, phrases);
    for (vector<string>::const_iterator it = phrases.begin(); it < phrases.end(); it++)
        cout << '"' << (*it) << '"' << endl;

    return 0;
}

実際に動かしてみるとこんな感じになります。

C:\Program_1\vs8\regex_test_mb\debug>split_test.exe
  foo, bar,  baz, ,ngan gu  , hogehu,,ga-- 
"  foo"
"bar"
"baz"
""
"ngan gu"
"hogehu"
""
"ga-- "

C:\Program_1\vs8\regex_test_mb\debug>

はてブがより便利になるような改善となるなら期待します。2007年06月18日 16時50分02秒

関係ないのですが、仕事の関係で土日が丸々つぶれてしまいました。今日は職場から朝帰りでそのまま代休なのですがw、おかげでせっかく時間もできたので、旬な話題にひとつ触れておこうかと思います。

問題点

はてなブックマークはおいらも最近活用させていただいています。主に俺熊による拙ブログ記事のカテゴリ整理と、他所で見つけた「気になる」記事のブックマークが目的です。

ブックマーカーとしては以上のとおりなのですが、それに加えて、はてなブックマークのトップページに浮上する人気エントリーも、注目される話題やネタを扱う記事を見つける手がかりのひとつとして活用しています。

今回の話題で注目すべきは、どちらかというと後者のほうなのではないかと思われます。今のところ、ネガティブブックマークが記事の書き手に与える心象、という部分が最も注目されており、それは確かに重要な課題ではあるのですが、一方で対策が施されることによって、ユーザーに不便を強いるようなことはできるだけ避けるべきです。

池田信夫氏は以下のように書いていますが、

同様にネットワークでも、イナゴが群がってS/N比が下がると、ブログの社会的評価が下がる。そうすると、価値の高い記事を書く人にとっては、ブログで得られる評価よりイナゴに食われるコストのほうが大きくなるので、質の高い記事は出てこなくなる。そうすると価値の低い記事ばかりが出回ってS/N比がさらに下がる・・・という悪循環によって誰もブログを読まなくなり、悪貨が良貨を駆逐するわけだ。私も、最近はヤフーの「ブログを含めない」という検索オプションを使っている。

実際には何が起こっているのかというと、価値の高い記事を書く人は決して減ってはいないのだけど、その代わり、価値の高くない記事が不当にはてなブックマークのトップページで「人気エントリー」としてピックアップされるようになってしまっている。 池田氏のいうのとは違った形で既に問題は発生しているのです。これは由々しき問題です。

最近、「人気エントリー」でタイトルを見て気になる記事のリンク先に飛んでみると、言っちゃあアレなんですがなんだかあんまり大したことないことが書いてあったりして (最近だとこれとかこれとか)、がっかりしながらはてブユーザーのコメントを見に行ってみると、これまた罵倒だらけのネガティブブックマークの渦でさらにげんなり、みたいな事が結構多い。内容が薄いと思うのであればブックマークなんてしなきゃ良いのに、突っつき甲斐のありそうな、弄って楽しそうな記事を見つけてしまうと、ついついブクマで突っついてしまう。そういう人たちが増えた結果、トップページの「人気エントリー」におけるノイズが高くなってきていて、本当に価値のある記事が拾いにくくなってしまっているのは確かだと思います。

個人的には、この傾向を逆に利用する記者やブロガーも結構出てきているんではないかと思っています。特に、はてなコミュニティに対する非難は、ブックマークを集めやすい。それでいて程よくあからさまな突っ込みどころが用意されていたりするとなおさらです。みんな釣りだと分かっていて食いつくんですよね。で、「人気エントリー」に浮上して、多くのはてなユーザーがニヤニヤしながら注目するようになる。でも、その一連の流れで一番ニヤニヤしているのは、実は釣堀を提供している記者やブロガー本人なんじゃないの? って、そんな光景を見かけるたび、いつも思ってしまうわけです。

実際に行われている対処

さて、池田氏が示した逆淘汰の説明で、彼はユーザーはブログを読まなくなる、と書いていますが、おいらはそうではなくて、このまま行けばピンポイントに「はてなブックマークの人気エントリーが見向きもされなくなる」という方向へと近づいていくのではないかと危惧しています (もちろん、そもそもネット利用の母数から見れば、はてなブックマークを活用する人の数は決して多くはないようで、そういう意味では市場における劇的な変化といえるほどの、目に見える形での衰退までには時間はかかるでしょうが、それでもここ最近のスラッシュドットジャパンなんかに見られるような微妙な寂れ感は少しずつですが出てくるでしょうね)。そして、こうした現状に対してユーザーが実際にとっている対処としては、「ブログを見ない」ではなく、「信用しているブログだけを見に行く」となるわけです。feed meterあわせて読みたいなんかは、そのような対処を行っているユーザーにとって、新たに信用できそうなニュースソースを獲得するための情報源として、これから利用は増えていくんじゃないかと感じています。

解決策

では、そういったサービスに淘汰されてしまうことを防ぐために、はてなブックマークとしてはどのような対策を講じる必要があるでしょうか? 以下は、おいらの個人的な提案です。

ようは、ネガティブブックマークが目立ちすぎていることが、さまざまな弊害を引き起こす原因であると考えられます。とはいえ、これを完全に否定してしまうことは、情報の有益性という意味ではあまり感心しません。確かに、罵倒の言葉をネット上に撒き散らす行為には感心できませんが、一方で、辛らつな意見とはいえ、参考になる、考えさせられるコメントも多く見受けられます。

「しればいいのに」という言葉が池田氏の記事で紹介されているので、それを開発した高木浩光氏のブックマークを例に挙げるならば、[good] タグと [bad] タグを用いて、どの記事を信頼し、どの記事を信用してはならないかが情報として集約されているのは、その手の情報を常に学び、取り入れていかなければならない人間としては、非常にありがたいことです。[bad] タグのついたコメントはそのほとんどが辛辣なものですが、同じ業界にいる人からすれば、そこから学ぶべきものも非常に多くあり、情報としては有用です。

「言葉を慎め」という意見も理解できますが、それによってこのような有用な情報を提供する人々のモチベーションが損なわれるようなことがあってはなりません。とまで書いてしまうとさすがに擁護が過ぎるというものではあるのでしょうが、あまりに窮屈に過ぎれば、それこそ池田氏が危惧するとおり、質の高い記事は出てこなくなる、ということになってしまうでしょう。

そこで、おいらとしては、ネガティブブックマークを規制するのではなく、逆に、そのブックマークがポジティブなものなのかネガティブなものなのかが、システム上明確になるようにしてあげればよいのではないかと思います。つまり、高木氏の使う [good] タグや [bad] タグに相当する機能を、タグとは別に特別に用意してあげればいいのです。

そして、(ここが重要なのですが) 例え多くのブックマークがつけられた記事であっても、その多くがネガティブブックマークであるようならば、トップページの「人気エントリー」には浮上しない、というルールを設けるべきです。こうすることで、ブックマーカーの行動が特別に制限されることのないまま、ユーザーが質の低い記事に不当に誘導されることも少なくなり、結果としてはてなブックマークへの信頼も高くなる、というわけです。

kids goo 的なフィルタリングは必要か?

kids goo や Google AdSense がやっているような、特定の用語に対する単純なフィルタリングは必要でしょうか? おいらはシステムにそうした機能を盛り込むことには反対です。しかし、一方で、被ブックマーク記事の執筆者からのクレームに応じて、罵詈雑言や誹謗中傷、脅迫行為を繰り返すユーザーに対しては注意喚起し、あるいは利用停止を視野に入れて個々のケースにおいて検討する、といった体制を整えていくことは、必要なのではないかと思っています。

逆に言えば、そういう類のものではなく、辛辣とはいえ単に反対意見を述べているだけのユーザーに対するクレームに対して、はてなはユーザーを守るべく、強硬な姿勢を貫かねばなりません。すなわち、一定の基準、ルールを明白にした上で、そのルールに則ってフェアであることが求められます。

Web サービスが「サービス」である以上、そういう対外事務的な部分にも人的リソースを供給してゆく必要があるのは当然でしょうし、すべきです。

鉄道各社は顧客を冷凍車の積荷のソーセージだとでも思っているんだろうか?2007年06月20日 22時52分18秒

帰りの電車で風邪引きそうになった。つうか引いたかも。目は充血してるし喉も痛いし。。。何なんだあの冷房設定は。頭おかしいとしか思えねーよ。

人生いろいろ、無限もいろいろ。2007年06月29日 00時33分20秒

まぁ、2n の n が整数なら、そこに奇数は含まれないからなぁ。数式を書き換えるしかないけれども、書き換えが許されない数式かもしれないし。

例えば癩予防法による強制隔離政策なんかは、その時代においては多くの市民にとって書き換えることの許されない数式だと認識されていたんではないかと思う。そういう時代の真っ只中において、当事者にとって「希望」などという言葉は、現実味のないキレーゴト、世迷いごととしか思えなかっただろう。

以下、思ったことをつらつらと。

  • 社会を変えるのは難しい。自分を変えるのは、場合によっては不可能だ。
  • 「無限の可能性」という言葉は、「可能性は 0 じゃない」という言葉に似ている。さまざまな願いに対してそれぞれ可能性はあるけれども、ピンポイントで焦点をあわせてみるとその可能性は限りなく低かったりもする。
  • 最初から不可能に見えるだけ、という可能性もある。それ自体は不可能だが、代替可能な方法がいくらでもあるという可能性もある (例えば年金なら、国がだめでも民間で、それもないなら自力貯金で代替可能かもしれない)。

とりあえずそんだけ。。。

社会が気に食わないなら自分を変えろ。それが嫌なら耳を塞ぎ、口をつぐんで生きろ。それも嫌なら…? (攻殻機動隊だっけ?)

まぁ、無限の可能性とやらを信じてテロだなんだに走るくらいなら、今のルールでできることの中から生き方を選んでいったほうが現実的だ罠。程度にもよるけど。

もっとも、ルールだとかなんだとか言うのとも違うもっと深い部分で苦しんでいる人のほうが、今の時代には多い気もするけどね。

結局、この手の話って、無下に「~なんじゃないかなぁ?」で済ませられても、そこにリアルを感じさせてくれないことには、いまいち説得力が沸いてこないのよね、とは思う。だから慎重さを期そうとすると、経験的に見て、どうしても悲観的にならざるを得なくなる。そういうことなんじゃないかなぁ。

なんてグダグダ書いていたらまた今日も夜更かしになっちゃったよ。寝るっ ぐぅ