2011年12月31日土曜日

[python] 今年最後の大修整!colorizeのオプションを大幅変更!

まぁ、やったことは別に大したことではないけども。
以前作った標準出力に色を付けるコマンド colorizeの、オプション回りを修正した。
前の記事
結構派手に変えた。前のオプションは全削除。

ソースはここ。
kokukuma / python-colorize

colorizeの使い方


一番簡単な使い方はこれ。
$ colorize.py karino

任意に色を指定するために4つのオプションを持っている。
簡単な色と範囲の指定には「-c」、「-r」オプションを使用する。
cは色の指定。rは正規表現を使った範囲の指定。
使い方は、たとえばこんな感じ。
$ colorize.py -c green -r '^.*$' karino
$ colorize.py -c blue -r 'kari' karino


もっと複雑なルールを設定するために、
設定ファイルを書くことができる。
デフォルトのパスは、~/.colorize.yml
形式は見ればわかる。

たとえばこんな感じ。
$ colorize.py -s errorlog [error]

たとえばこんな感じ。
$ ping google.com | colorize.py -s ping

どんな出力になるかは、試してみてのお楽しみ。


また、デフォルトパス以外の設定ファイルを読み込むこともできる。
たとえばこんな感じ。
$ colorize.py -f '/home/karino/test_colorize.yml'  -s errorlog [error]


optparseを使ったオプション管理

大きな変更点はここ。
これを使えば、オプションと標準入力をしっかり区別することができる。
管理も楽。ヘルプもつけれる。
パーサを作成し、それを使ってオプションやそのほかの引数を取得する。

パーサの作成はこんな感じ。
def build_option_parser():    
"""Make Option Parser"""
    parser = OptionParser()
    parser.add_option(
            '-f', '--configuration-file-path',
            help="read configuration from. (default: '~/.colorize.yml')",
            default='~/.colorize.yml'
            )
    parser.add_option(
            '-s', '--color-scheme',
            help="set scheme of colorize. (default: 'all')",
            default="all"
            )
    parser.add_option(
            '-r', '--regular',
            help="set regular expression. (default: '^.*$')",
            default=r"^.*$"
            )
    parser.add_option(
            '-c', '--color',
            help="set color. (default: 'red')",
            default="red"
            )
    return parser

オプション・引数の取得はこんな感じ。
parser = build_option_parser()
    opts, args = parser.parse_args()

    # get options / color_scheme
    try:
        config_path = opts.configuration_file_path
        color_scheme = opts.color_scheme

        if color_scheme == 'all':
            color_scheme = [{
                    'regular':'(' + opts.regular + ')',
                    'color':opts.color
                    }]
        else:
            color_scheme = read_color_scheme(color_scheme, config_path)

    except Exception, e:
        parser.error(e)

[vim][python] ふははは!読める!読めるぞ!

その経緯


pythonを書くとき、classやdefを折りたたむためのスクリプトを書こうと思いました。

とりあえず探してみると、あった。
python_fold : Folding expression for python

中身を見てみて、少しテンションあがった。

読める!。downloadしてきたプラグインが読める!

少しはvim scriptが読めるようになってきました。

このpython_foldを読んでみた感想は・・・。
長い。そして、if文の嵐。
個人的に使うならもっとコンパクトにまとめれそうな気がしました。



理想


ロジックとしては、以下のような感じ。
① classやdefを見つけたら、その行のインデントにあわせて、fold開始。
② 直下が空行かつ、次の非空行のインデントが現在のfoldlevelより小さければ、foldを閉じる。
③ それ以外の場合は、前の行と同じ操作。

これをvim scriptで書くとこんな感じになるはず。

" 折り畳みレベルを設定する関数(python)
function! PYTHONFoldSetting(lnum)

    " 現在の行
    let line = getline(a:lnum)
    let ind  = indent(a:lnum)
    let flev = foldlevel(a:lnum)

    " 次の行
    let line1 = getline(a:lnum + 1)

    " 次の非空行
    let nind = indent(nextnonblank(a:lnum + 1))

    " Classes and functions get their own folds
    if line =~ '^\s*\(class\|def\)\s'
        return '>'. (ind / &sw + 1)
    elseif empty(line1) && (nind / &sw + 1) <= flev
        return '<'.flev
    else
        return '='
    endif
endfunction
しかし、動かないorz。 foldlevel関数でとってこれてないのかな・・。


妥協

どうしても動かないので、 仕方なしで以下のように妥協。
function! PYTHONFoldSetting(lnum)
    " foldlevelは3まで
    set foldnestmax=3

    " 現在の行
    let line = getline(a:lnum)
    let ind  = indent(a:lnum)
    let flev = foldlevel(a:lnum)

    " 次の行
    let line1 = getline(a:lnum + 1)

    " 次の非空行
    let nind = indent( nextnonblank(a:lnum + 1) )

    " Classes and functions get their own folds
    if line =~ '^\s*\(class\|def\)\s'
        return '>'. (ind / &sw + 1)
    elseif ind > nind && empty(line1) && (nind / &sw + 1) == 1
        return '<'.1
    elseif ind > nind && empty(line1) && (nind / &sw + 1) == 2
        return '<2'
    elseif ind > nind && empty(line1) && (nind / &sw + 1) == 3
        return '<3'
    else
        return '='
    endif
endfunction

まぁ動作としては変わらないし、3段階以上ネストすることもないだろうから、
実用上これで良いかもしれないが、
やっぱ気持ち悪いな・・・。

[vim] カーソル下のキーワードをhelp検索するためのキーバインド

カーソルの下にある単語でvimのhelpを引くためのキーバインド。
なんのことはない単純な設定だが、異常に便利。

nnoremap <C-h> :<C-u>help<Space><C-r><C-w><CR>

今まで、:h getline とか打ってたのが馬鹿みたい。


その後・・・。
やっぱこっちにした↓
nnoremap H; :<C-u>help<Space><C-r><C-w><CR>

2011年12月29日木曜日

[vim] phpのfunctionを折りたたむ設定をした。

目指せ!一日 一vimscript.

IDEでよく見るfunction毎に行を折りたたむあれ。
これをやると、


が、




こんな感じになる。
絵、見づらいな。

ここを参考にしました。
折り畳み嫌いの男が一夜でFolding freakにまでなった話



folding設定のやり方

foldmethodにexprを指定すれば、
行ごとに、どのようにfoldingするかを指定することができる。
foldmethodにはほかにもいくつか指定方法があるが今回はこれで。


php用の設定

phpの場合、この関数で定義される条件に沿ってfoldingする。
function! PHPFoldSetting(lnum)
    let l:line = getline(a:lnum)
    if l:line =~ 'function'
        return '>1'
    elseif getline(a:lnum + 1) =~ ' \* '
        return 0
    elseif getline(a:lnum) =~ ' \* '
        return 0    
    else        
        return '='    
    endif
endfunction


bash用の設定

bashの場合、この関数で定義される条件に沿ってfoldingする。
function! BASHFoldSetting(lnum)
    let l:line = getline(a:lnum)
    if l:line =~ '^.*() {'
        return '>1'
    elseif getline(a:lnum) =~ '^}'
        return '<1'
    elseif getline(a:lnum - 1) =~ '^}'
        return '0'
    else
        return '='
    endif
endfunction

ファイルオープン時の設定読み込み

phpならPHPFoldSetting、bashならBASHFoldSettingを読み込む。
autocmd BufEnter *.php set foldmethod=expr foldexpr=PHPFoldSetting(v:lnum)
autocmd BufEnter .bashrc set foldmethod=expr foldexpr=BASHFoldSetting(v:lnum)

キーバインドを設定

" folding用キーバインド
noremap [space] 
nmap  [space]
noremap [space]j zj
noremap [space]l zo
noremap [space]k zk
noremap [space]h zc
noremap [space]i zMzv
noremap [space]m zm


これ、便利だわ。

2011年12月28日水曜日

[vim] 日本語ヘルプをインストール

最近、何かと、vimのヘルプを参照する機会が多くなってきた。
日本語でよもう。
vim scriptでわからないことものあったら、
ググるよりヘルプ見た方がいい。

日本語に翻訳されたvimエディタのヘルプをインストールして使用する。
ここの↑劣化コピー。


インストール

① 日本語ヘルプをダウンロード
コマンドラインで以下を実行。
git clone git://github.com/vim-jp/vimdoc-ja.git
cd vimdoc-ja
cp doc/* ~/.vim/doc

② ヘルプの設定
以下をvimrcに書き込む。
helptags ~/.vim/doc
set helplang=ja,en

ヘルプの引き方


: h (調べたいこと)
: helpg (調べたいこと)
h → help
helpg → helpgrep

英語のヘルプを引きたいときは。


: h (検索したいこと)@en
@jaをつければ日本語。

2011年12月27日火曜日

[vim] vimを起動したカレントディレクトリを見て、参照するtagファイルを変える方法。

そろそろ、タグジャンプが使いたくなってきたので、ctagsをインストール・設定した。


ctagsインストール

$ sudo yum install ctags

適当にインストール。

ctagsのタグ作成手順・シェル


$ ctags -f ./tags -R ./lib/model/
$ ctags -a -f ./tags -R ./lib/util/ 
-f : tagファイルの名前を指定
-R : 再帰的にディレクトリを参照
-a : 既存tagファイルがあれば末尾から追記。

普段、参照先のモデルやライブラリを大きく変更する事はないので、
bazarlレポジトリのアップデートと一緒にtagファイルを作成するように
シェルに組み込んだ。

ctagsの設定ファイルもあるらしいが、
シェルに書いとけば良いやと思って調べてない。


tags読み込み

下記を、vimrcに書き込んだ。
let current_dir = expand("%:p:h")
" 開くディレクトリによって、読み込むtagsを切り替える
if matchstr(current_dir , "tsubasa_source/tsubasa/") == "tsubasa_source/tsubasa/"
    set tags=/home/karino/tsubasa_source/tsubasa/tags
endif
if matchstr(current_dir , "tsubasa_source/tsubasa_invite_incentive") == "tsubasa_source/tsubasa_invite_incentive"
    set tags=/home/karino/tsubasa_source/tsubasa_invite_incentive/tags
endif

vimを起動したディレクトリを取得し、
特定のディレクトリ名がマッチしたら、
tagsファイルを読み込む。
「tsubasa_source/tsubasa」を含むなら、tsubasa/tags。
「tsubasa_source/tsubasa_invite_incentive」を含むなら、tsubasa_invite_incentive/tags。
見たいな感じ。

これだけなのに調べるの結構大変だった。

2011年12月24日土曜日

[vim] NERDTreeをインストール

NERD-Tree

Vim Essential Plugin: NERDTree

便利そうだったので入れた。
加えて、初めて、autocmd使った
vimの設定をしてみた。

① インストール

The NERD tree : A tree explorer plugin for navigating the filesystem
からダウンロード。

$ wget http://www.vim.org/scripts/download_script.php?src_id=11834
$ mv download_script.php\?src_id\=11834 ds.zip
$ unzip ds.zip
$ cp doc ~/.vim/
$ cp nerdtree_plugin ~/.vim/
$ cp plugin ~/.vim/


② grep機能の追加

nerdtree plugin to integrate nerdtree with :grep : Forked from
$ wget https://gist.github.com/gists/414375/download
$ mv download dl.tar.gz
$ tar -xvzf dl.tar.gz
$ cd gist414375-24c6049f621f07db839e8cdd133e396756d642db/
$ cp grep_menuitem.vim ~/.vim/nerdtree_plugin/


③ 基本的な使い方

NERDTree : ツリー型エクスプローラ
起動:コマンドモードでNERDTree

o : ディレクトリを開く or ファイルを開く
O : 再帰的にディレクトリを開く
s : 縦に開く
m : メニューを開く


④ 使いやすいように設定

引数なしでvimを開いたらNERDTreeを起動、引数ありならNERDTreeは起動しないように
vimrcに以下を記述した。
let file_name = expand("%")
if has('vim_starting') &&  file_name == ""
    autocmd VimEnter * NERDTree ./
endif

2011年12月23日金曜日

LinuxにDropboxをインストールする。

LinuxにDropboxをインストールしてみた。
かなり便利。

さくらVPSでDropboxをX11なしで使う

① シェルをダウンロード
$ wget http://www.dropbox.com/download?dl=packages/dropbox.py
$ chmod 777 dropbox.py

② 起動すると、dropboxのダウンロードが始まる。
$ ./dropbox.py start
Starting Dropbox...
The Dropbox daemon is not installed!
Run "dropbox start -i" to install the daemon
$ ./dropbox start -i
Starting Dropbox...
Dropbox is the easiest way to share and store your files online. Want to learn more? Head to http://www.dropbox.com/

In order to use Dropbox, you must download the proprietary daemon. [y/n] y
Downloading Dropbox... 100%
Unpacking Dropbox... 100%
Dropbox isn't running!
Done!

③ マシンとアカウントをリンクする。
$ ./.dropbox-dist/dropbox
このクライアントはアカウントにリンクされていません...
このマシンをリンクするには https://www.dropbox.com/cli_link?host_id=792418c797c32c59202ee249101a5bfc&cl=ja を開いてください。
このクライアントはアカウントにリンクされていません...
このマシンをリンクするには https://www.dropbox.com/cli_link?host_id=792418c797c32c59202ee249101a5bfc&cl=ja を開いてください。
・・・

シェルをこのままにして、別のPCからでもURLへ接続して、Dropboxにログインする。


④ Dropboxのデーモンを起動する
$ ./dropbox.py start
Starting Dropbox...Dropbox isn't running!
Done!

これで、HOMEにできたDropboxがリンクする。

2011年12月18日日曜日

「標準出力に色をつけたい!」と思ったときは、このコマンド使ったらいいと思う。

「標準出力の色を変更するためのコマンド」を作った。

これを使えば、tailしているログに任意に色をつける事はもちろん、
pingなど標準出力されるもの全部に色をつける事ができる。
複雑な着色ルールでも、yaml形式の設定ファイルで簡単に設定できる。
結構うまくできた気がする。

経緯

この前、標準出力に色をつける方法を知った。
そのログ、色つきでtailしたくないですか?

ふと探してみると、色つきtailがあった。
pctail - CCZE に似た、Python で書かれた色つき Tail
やってる事は同じ。何を使って置換するかが違うだけかな。

チョット読んでみたが・・・、色のつけ方いまいち。
せめて、IPアドレスは色変えてほしい。

そしてログだけではもったいない。
いろんなコマンドの標準出力に色をつけたい。

しかし、前みたいにperlをパイプラインでつなぎまくるのはいけてない。(って言われたw)遅くなるし。
そこで、標準出力の色を変更するためのコマンドを作った。


ソース


結構長くなったので、githubに置く。
kokukuma / python-colorize

初めてpython書いたので、
めんどくさい書き方してる場合があるかも知れない。
誰か治してくれないかな・・・。

あ、pyyaml、インストールしておいてください。
PyYAMLモジュールを使ってPythonからYAMLを読む


使い方

$ colorize -a (色) (対象文字列)
$ colorize -r (カラールール名) (対象文字列)
1つ目の書き方では、対象文字列すべてが色変更の対象となる。
2つ目の書き方では、対象文字列を指定したカラールールに則って色変更を行う。
カラールールの形式はyml。
ルール名の下に、マッチさせる正規表現と色を指定する。
正規表現はダブルコーテーションで囲む。

(カラールール名):
    (ルール名):
        regular:"(対象文字列をあらわす正規表現)"
        color:(色)
    (ルール名):
        regular:"(対象文字列をあらわす正規表現)"
        color:(色)


使用例

tailしているログに色をつけたい場合はこんな感じ。
$ tail -f log |  colorize -a errorlog

pingに色をつけたい場合はこんな感じ。
$ ping google.com | colorize -a ping

このとき使っているconfig.ymlはこんな感じ。
errorlog:
    rule1:
        regular:"\[[Ee]rror\]"
        color:red
    rule2:
        regular:"\[emerg\]"
        color:green
ping:
    rule1:
        regular:"[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*"
        color:yellow
    rule2:
        regular:"[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*"
        color:under
    rule3:
        regular:"from"
        color:red

その後、
前後にgrepつけれない問題はまだ残っている。。
結構致命傷だな。

2011年12月15日木曜日

もう何度も何度もやっている気がするが、今後また作るときの事を考えて、改めてここで、PHP Extension の作り方をまとめておく。

自分がPHP Extensionを作ろうと思ったときに、
「とりあえず開いて書き方ぱくるためのページ」として、
これを書いておく。解説は他のサイトを確認する。
Zend API: PHPのコアをハックする
ここはあくまで、こうやって書いたら動いたってメモ。

※ 前提条件として、PHPをソースからコンパイルしてある事とする。

ソースのパス : /usr/local/share/php-5.3.8/
extension_dir: /usr/lib64/20090626
作成するextensionの名前: mywork


1、スケルトンの作成




cd /usr/local/share/php-5.3.8/ext/
./ext_skel --extname=mywork
cd mywork


2、とりあえずコンパイル




① config.m4を修正
inl 以下をコメントアウトからはずす。
PHP_ARG_WITH(eigen, for eigen support,
Make sure that the comment is aligned:
[  --with-eigen             Include eigen support])

② コンパイル
# phpize 
# ./configure
# make
これで、./modules内に、mywork.soが作成される。
されなかったらなんか間違ってる。

③ PHPにextensionを読み込ませる。
# ln -s /usr/local/share/php-5.3.8/ext/mywork/modules/mywork.so /usr/lib64/20090626/
加えて、php.iniに「extension=mywork.so」を記入しておく。
make installしても良いが、これから何度もコンパイルするたびにmake installするのがめんどくさいから、シンボリックリンクはる。



3、引数取得・戻値返却



こんなPHP extensionを書くためにやる事。


① php_mywork.h
// 関数名を定義
PHP_FUNCTION(MYWORK);

② mywork.c
/* zend_function_entry の中に、MYWORKの行を追記 */
const zend_function_entry kakasi_functions[] = {
    PHP_FE(confirm_kakasi_compiled, NULL)       /* For testing, remove later. */
    PHP_FE(MYWORK, NULL)
    PHP_FE_END  /* Must be the last line in kakasi_functions[] */
};

~~~
PHP_FUNCTION(MYWORK){    
    // 値定義
    int   str_len;
    char *str;

    // 引数の取得
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
        "s", &str, &str_len) == FAILURE) {
        return;
    }
  // 戻り値作成(文字列)
  RETURN_STRINGL(str,str_len,0);
}
これで、引数「引数」が戻される。
longやdoubleなどの返却は、同じようなマクロを使って返却する。詳しくは、以下を参照。
Zend API: PHPのコアをハックする
配列やオブジェクトの返却はチョットややこしい。

・配列を返却
PHP_FUNCTION(MYWORK){    

~~~
  // zvalの定義
  
    zval *return_array;
    char *separated_word
    char words[1024];
    words="test,test,test,test";

  // 配列を表すzvalを作成
    MAKE_STD_ZVAL(return_array);
    if(array_init(return_array) != SUCCESS){}

    // 文字の分割 
    separated_word = strtok( words, "," );
    while( separated_word != NULL ){
        // 配列に値を追加する。
        add_next_index_stringl(return_array,separated_word,strlen(separated_word),1);
        separated_word= strtok( NULL, "," );  /* 2回目以降 */
    }

    // 配列を返却
    *return_value = *return_array;
    zval_copy_ctor(return_value);
}

・オブジェクトを返却
PHP_FUNCTION(MYWORK){    

~~~
    // 返却オブジェクトの生成
    zval *wordset;
    MAKE_STD_ZVAL(wordset);
    if(object_init(wordset) != SUCCESS){}

    // プロパティを設定
    add_property_stringl(wordset,"base",str,strlen(str), 1);
    add_property_stringl(wordset,"hira",hira,strlen(hira),1);
    add_property_stringl(wordset,"kata",kata,strlen(kata),1);
    add_property_stringl(wordset,"alph",alph,strlen(alph),1);

    // オブジェクトの返却
    *return_value = *wordset;
    zval_copy_ctor(return_value);
}



3、クラス作成



こんなPHP extensionを書くためにやる事。
member1;
$obj->member2;
$ret = $obj->method();
?>

① php_mywork.h
// 以下を追記する。
PHP_FUNCTION(mywork);
PHP_METHOD(mywork, method);
static zend_class_entry *mywork_ce;

② mywork.c
/* zend_function_entry の中に、MYWORKの行を追記 */
const zend_function_entry kakasi_functions[] = {
    PHP_FE(confirm_kakasi_compiled, NULL)       /* For testing, remove later. */
    PHP_FE(MYWORK, NULL)
    PHP_ME(MYWORK, method ,NULL)
    PHP_FE_END  /* Must be the last line in kakasi_functions[] */
};

~~~
/* PHP_MINIT_FUNCTION(mywork) の中に、MYWORKの行を追記 */
PHP_MINIT_FUNCTION(mywork)
{
    /* If you have INI entries, uncomment these lines
     REGISTER_INI_ENTRIES();
    */
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "", mywork_functions);
    mywork_ce = zend_register_internal_class(&ce TSRMLS_CC);

    zend_declare_property_string(mywork_ce,"member1", strlen("member1"),"初期値", ZEND_ACC_PUBLIC);
    zend_declare_property_string(mywork_ce,"member2", strlen("member2"),"初期値", ZEND_ACC_PUBLIC);

    return SUCCESS;
}

~~~
PHP_FUNCTION(mywork){
    return;
}

PHP_METHOD(mywork, method){

    // 定義
    zval *obj, *member1, *member2;

    // メンバ変数の取得
    obj = getThis();
    member1 = zend_read_property(Z_OBJCE_P(obj),obj, "member1",strlen("member1"), 1 TSRMLS_CC);
    member2 = zend_read_property(Z_OBJCE_P(obj),obj, "member2",strlen("member2"), 1 TSRMLS_CC);
    
  // 戻り値作成(文字列)
  RETURN_STRINGL(member1,strlen(member1),0);
}



番外、C++を使いたい場合



CではなくC++を使いたい場合の今までと異なる点を上げる。

① config.m4
inl コンパイラの環境変数を設定
CC=/usr/bin/gcc
CFLAGS="-g -O2 -lstdc++"
CXX=/usr/bin/g++
CXXFLAGS=-fPIC

~~~
inl 拡張子をc→ccに変更する。
PHP_NEW_EXTENSION(eigen, eigen.cc, $ext_shared)


② ファイルの拡張子
mv mywork.c mywork.cc

③ mywork.cc
// #includeを extern "C"で囲む
extern "C"{
    #include "php.h"
    #include "php_ini.h"
    #include "ext/standard/info.h"
    #include "php_eigen.h"
}



2011年12月14日水曜日

そのログ、色つきでtailしたくないですか?

tailは便利だけど、白黒で見るのはすごく疲れます。
なので、色を付けてみたいと思います。
色をつけるにはANSI エスケープシーケンスを使えばよいらしい。


1、ANSI エスケープシーケンスとは。



ディスプレイに文字を表示する際のエスケープ。
つまり、今自分が使っているターミナルが、
受け取った文字列を表示する際の制御文字みたいなものらしい。

ANSI エスケープシーケンスを使うと、色を変えるだけでなく、
コマンドラインの表示をいろいろカスタムできるらしい。
ANSIエスケープシーケンスを使って端末に時計を表示するとか。

2、ANSIエスケープの書き方。


こんな感じ。
# karinoを赤色で標準出力
echo -e "\033[0;31mkarino\033[0m"

# karinoの背景を緑色で標準出力
echo -e "\033[42mkarino\033[0m"

# karinoにアンダーラインをつけて標準出力
echo -e "\033[4mkarino\033[0m"

複雑に見えるが、形式を把握できれば大丈夫。

5. ANSI エスケープシーケンス: 色とカーソル操作

色を変えるときの形式は、以下。
ESC[色m

bashでは以下のように書く。
「ESC」 → 「 \e 」or「 \033 」
「 [ 」 → 「 \[ 」

「色」の部分は、以下。
文字の色、背景の色、どちらもこのIDで指定する。
色ではないが下線とか点滅もできる。
【文字色】
Black 0;30
Blue 0;34
Green 0;32
Cyan 0;36
Red 0;31
Purple 0;35
Brown 0;33
Light Gray 0;37
Dark Gray 1;30
Light Blue 1;34
Light Green 1;32
Light Cyan 1;36
Light Red 1;31
Light Purple 1;35
Yellow 1;33
White 1;37

【背景色】
Black 40
Blue 44
Cyan 46
Red 41
Purple 45
Brown 43
Light Gray 47

【その他】
下線 4
点滅 5
色の逆転 7
非表示 8


3、マッチした部分を置き換える方法



標準出力されるログをハイライトさせる方法として、
以下のようなのがあった。
tail -f messages | perl -pe 's/[Ee]rror/¥e[1;31;43m$&¥e[0m/g' 
標準出力のキーワードをハイライト

これと同じ方法を使わせてもらう。


4、色を変えるスクリプト



loghighlight() {
    
    # ANSIエスケープシーケンスの定義
    RED_WORD="\e[0;31m"
    BLUE_WORD="\e[0;34m"
    GREEN_WORD="\e[0;32m"
    CYAN_WORD="\e[0;36m"
    PURPLE_WORD="\e[0;35m"
    YELLOW_WORD="\e[1;33m"
    GRAY_WORD="\e[0;37m"
    UNDER_LINE="\e[4m"
    DEFO="\e[0m"
    
    # 置換 
    while read line;do
    echo $line | /usr/bin/perl -pe "s/\[[Ee]rror\]/${RED_WORD}$&${DEFO}/g"    \
               | /usr/bin/perl -pe "s/\[client.*\]/${GREEN_WORD}$&${DEFO}/g"  \
               | /usr/bin/perl -pe "s/\[debug\]/${GREEN_WORD}$&${DEFO}/g"     \
               | /usr/bin/perl -pe "s/\[emerg\]/${GREEN_WORD}$&${DEFO}/g"     \
               | /usr/bin/perl -pe "s/\/(.*\/)(.*)/${PURPLE_WORD}$&${DEFO}/g" \
               | /usr/bin/perl -pe "s/\/(.*\/)(.*)/${UNDER_LINE}$&${DEFO}/g"  \
               | /usr/bin/perl -pe "s/PHP Fatal error:/${RED_WORD}$&${DEFO}/g"
    done
}

使い方は以下のとおり。
$ tail -f error.log | loghighlight
正規表現にマッチしたものを指定した色に変更して出力する。


5、問題点



遅い。
sedとか、awk getline使ったほうが速いかも。
whileとawk
全部perlで組んだほうがいいんじゃないだろうか。


その他、参考になったページ



Linux上でシェルが実行される仕組みを,体系的に理解しよう (bash 中級者への道)

ANSI Escape sequences


使っているうちに、いくつか問題が見つかった。
・tailの対象ファイルが2つ以上の場合、最初のファイル以外が出力されない。
・tailコマンドの前で、grep等をパイプで渡したものをloghighlightの対象とすると、ひとつも表示されない。
やっぱりwhile read以外でやりたいな。

その後、標準出力に色つけるコマンド作った。
「標準出力に色をつけたい!」と思ったときは、このコマンド使ったらいいと思う。

2011年12月8日木曜日

PHPで、漢字 → ひらがなに変換する方法を知っていますか?

mb_convert_kanaを使えば、
全角半角変換や、ひらがな→カタカナの変換は可能。
しかし、漢字→ひらがなの変換はできない。

関数リファレンス

漢字→ひらがなの変換をするためには
Mecabを使うかKakasiを使う必要がある。たぶん。
Mecabはphp拡張モジュールが準備されているが、
Kakasiはそれらしいものがなかった。

kakasiを使うPHP拡張モジュールを書いた。

php-kakasi

これを使えば、下のコードのように、
与えた文字列を、ひらがな、カタカナ、アルファベットに
変換することができる。
与える文字列は、ひらがな、カタカナ、漢字に対応している。

$kakasi = new KAKASI();
    $kakasi->word = "キャプテン翼";

    $wordset = $kakasi->reproc();

    echo "元キーワード:".$wordset->base."\n";
    echo "ひらがな変換:".$wordset->hira."\n";
    echo "カタカナ変換:".$wordset->kata."\n";
    echo "Alphabet変換:".$wordset->alph."\n";

この出力は以下。

$ php php_kakasi.php 
元キーワード:キャプテン翼
ひらがな変換:きゃぷてんつばさ
カタカナ変換:キャプテンツバサ
Alphabet変換:kyaputentsubasa


① インストール方法

こんな雰囲気。

$ git clone git@github.com:kokukuma/php-kakasi.git
$ cd php-kakasi/kakasi
$ phpize
$ ./configure
$ make
$ make install

あと、php.iniに、
「extension=kakasi.so」
って、書く。

※ kakasiは事前にインストールしておく。
※ もしかしたら、kakasi.so.2をincludeパスに移動 or ln -s する必要あるかも


その後、結構仕様変えちゃいましたw。
READMEよんでね。

2011年12月5日月曜日

対話的にBazaarを使うシェルを書いた。

今の開発環境でバージョン管理ツールにBazaarを使っているので、
よく使うコマンドをざっとメモった。
また、開発スタイルは集中型。

Bazaarユーザガイド

【開発スタイル】
① 集中型
集中型の開発
集中型の場合、全員で同じブランチを使う。
コミットするとローカルではなく、
マスターブランチにコミットされる。

② 分散型
分散型の開発
分散型の場合、開発者毎に自分のブランチを持つことになる。
コミットするとローカルブランチにコミットされ、
プッシュ・マージすることにより、
マスターブランチにアップする。


【コマンドまとめ】
① 初期設定で使うコマンド
$ bzr whoami (ユーザ名)<(メールアドレス)> // ユーザ名を設定する。
$ bzr checkout bzr+ssh://(レポジトリ先)   // チェックアウトを作成する。
$ bzr bind bzr+ssh://(レポジトリ先)       // コミットが行われるマスターブランチを変更する。
$ bzr unbind bzr+ssh://(レポジトリ先)     // コミットがローカルのみで行われるようにする。


② 日々の開発で使うコマンド
$ bzr status                     
$ bzr update                     
$ bzr log --forward --line       
$ bzr diff                       
$ bzr di                         
$ bzr marge                      


③ 今の開発環境では使わないコマンド
$ bzr clone bzr+ssh://(レポジトリ先) // クローン
$ bzr push bzr+ssh://(レポジトリ先)  // プッシュ
$ bzr pull                           // プル

今の開発環境は、「集中型の開発環境」であるので、
ローカルブランチを作成するクローンとかは使わない。


【カスタマイズ】

さらによく使う組み合わせでbashで関数を作ってみた。

① 対話型コミットシェル
変更点、コミットメッセージの入力を対話的にやってみた。
コマンド打ったほうが速い気もしなくもないが。

bzrc() {
    #--- check commit
    stty intr ^\?    
  stty erase ^H    
  
  #--- check commit  
    #bzr update
    bzr di

    #--- confirm commit  
    echo -n "Do you want commit? y or n> "
    read FLG_COMMIT

    if [ $FLG_COMMIT = 'y' ]; then
        echo ""
    elif [ $FLG_COMMIT = 'n' ]; then
        echo "Thank you."
        return
    else
        echo "Please Input y or n."
        return
    fi

    #--- get commit message 
    echo -n "Please input commit message > "
    read COMMIT_MSG

    #--- execute commit
    bzr commit "-m" "$COMMIT_MSG"
}

stty ~ ktermでバックスペースが効かない!
「stty ^H」は、入力待ちの段階で、バックスペースを効かせるために必要。

② 修正ファイルのピックアップ
リビジョン番号を渡すと、そのリビジョンで
修正されたファイルをピックアップしてくれる。
まぁ、bzr diffから文字列切り出してるだけだけど。

chkfile() {
    #--- get parameter  
    REV_NUMBER=$1

    if [ "${REV_NUMBER:-null}" = "null" ]; then
        echo
        echo "chkfile revision_number"
        echo
        return
    fi

    #--- execute bzr diff -c
    echo
    echo "=== add files"
    bzr "diff" "-c" "$REV_NUMBER" |
        grep     "=== added file "    |
        sed -e "s/=== added file '\(.*\)'/\1/"
    echo
    echo "=== modified files"
    bzr "diff" "-c" "$REV_NUMBER" |
        grep     "=== modified file "    |
        sed -e "s/=== modified file '\(.*\)'/\1/"
    echo

    return
}

③ リリースブランチへのマージ
merge() {
    #--- check commit
    stty intr ^\?          
    stty erase ^H
    
    #--- get and set parameter      
    RELESE_BRANCH="/home/karino/release"    
    TRUNK_BRANCH="/home/karino/tsubasa"    
    REV_NUMBER=$1    
    CDIR=`pwd`    
    
    #--- check parameter     
    if [ "${REV_NUMBER:-null}" = "null" ]; then        
     echo       
     echo "Please input revision_number"        
     echo        
    return    
    else        
     echo    
    fi


    #--- get commit message     
    echo "relese blanch : "$RELESE_BRANCH     
    echo "trunk blanch  : "$TRUNK_BRANCH  
    echo    echo -n "Do you want relese? (y/n) > "    
    read FLG_RELESE    
    
    if [ $FLG_RELESE = "y" ]; then        
     echo         
     cd $RELESE_BRANCH        
     bzr merge "--force -c " "$REV_NUMBER"        
     cd $CDIR    
    elif [ $FLG_RELESE = "n" ]; then        
     echo         
     echo "Thank you."
        echo
        return
    else
        echo 
        echo "Please Input y or n."
        echo
        return
    fi

    #--- return 
    return
}

KAKASIをCから使う。

cからkakasiを使う方法。
参考 : kakasi-2.3.4/doc/README.lib


① ソース
#include 
#include 
#include 
#include 
#include 
#define MYBUFSZ 1024
int UtfToEuc(char *str , char *outs);
int EucToUtf(char *str , char *outs);

int
main(int argc, char *argv[]){    
//--    
    char *srcStr, *dstStr;    
    char *srcStr2, *dstStr2;    
    char buffer[256];    
    int  strLen;    
    char *option[] = { "kakasi", "-JH"};   
    int ret;   
 //--   
    srcStr  = argv[1];   
    srcStr2 = srcStr;    
    UtfToEuc(srcStr,srcStr2);    
    ret = kakasi_getopt_argv(2, option);   
    if(ret == 0)
    {       
        dstStr2 = kakasi_do(srcStr2);       
        dstStr  = dstStr2;        
        printf(dstStr2);        
        if(dstStr2)
        {
            //--
            EucToUtf(dstStr2,dstStr);
            printf(dstStr);
            kakasi_free(dstStr2);
            dstStr  = NULL;
            dstStr2 = NULL;
            return 1;
        }
        else
        {
            printf("ERROR2\n");
        }
    }
    else
    {
        printf("ERROR1\n");
    }

    return 0;
}

int EucToUtf(char *str , char *outs)
{
    iconv_t ic;
    char str_in[MYBUFSZ+1];
    char str_out[MYBUFSZ+1];    char *ptr_in = str_in;
    char *ptr_out = str_out;
    size_t mybufsz = (size_t)MYBUFSZ;

    strcpy(str_in,str);
    ic = iconv_open("UTF-8","EUC-JP");
    iconv(ic, &ptr_in, &mybufsz, &ptr_out, &mybufsz);
    iconv_close(ic);
    strcpy(outs,str_out);

    return 0;
}

int UtfToEuc(char *str , char *outs)
{
    iconv_t ic;
    char str_in[MYBUFSZ+1];
    char str_out[MYBUFSZ+1];

    char *ptr_in = str_in;
    char *ptr_out = str_out;
    size_t mybufsz = (size_t)MYBUFSZ;

    strcpy(str_in,str);
    ic = iconv_open("EUC-JP","UTF-8");
    iconv(ic, &ptr_in, &mybufsz, &ptr_out, &mybufsz);
    iconv_close(ic);
    strcpy(outs,str_out);

    return 0;
}

ぶっちゃけ、Cよくわからず、適当に作った感は否めない。
今度ちゃんとCの勉強しよう。
って、いっつもも思う。


② コンパイル
$ sudo ln -s /usr/local/lib/libkakasi.so.2 /usr/lib64/libkakasi.so.2
$ gcc -lkakasi -o kakasi kakasi.c

普通にインストールしたら、/usr/local/lib/にsoファイルができた。
cから使おうとすると/usr/lib64から読もうとしていたので、
シンボリックリングを張った。


③ 実行
$./kakasi 狩野達也
かのたつや

辞書、追加しようかな。

漢字→かな(ローマ字)変換プログラム KAKASIのインストールと使い方

漢字→かな(ローマ字)変換プログラム KAKASI
漢字とかひらがなとかに変換するツール。

① kakasiのインストール、
$ wget http://kakasi.namazu.org/stable/kakasi-2.3.4.tar.gz
$ tar zxvf kakasi-2.3.4.tar.gz
$ cd kakasi-2.3.4
$ ./configure
$ make
$ sudo make install
普通どおり。

2、コマンドラインからの利用
[karino@115x125x111x181 ~]$cat test
漢字混じりの文章
[karino@115x125x111x181 ~]$cat test | nkf -e | kakasi -JH | nkf -w
かんじまじりのぶんしょう
[karino@115x125x111x181 ~]$cat test | nkf -e | kakasi -JH | kakasi -Hk |nkf -w
カンジマジリノブンショウ
[karino@115x125x111x181 ~]$cat test | nkf -e | kakasi -JH | kakasi -Ha |nkf -w
kanjimajirinobunshou

変換前と変換後を指定する。

J : 漢字
H : ひらがな
a : ローマ字
K : カタカナ

※ kakasiはeuc-jiで動作するようなので、
使用する前後で文字コードを入れ替えている。


3、辞書の追加
kakasi に辞書を追加する。
こんなかんじ。


追記
カタカナ、小文字「k」じゃなくて大文字「K」
にしないと効かなかった。

-JH : 漢字→ひらがな
-KH : カタカナ→ひらがな
-Ha : ひらがな→アルファベット

2011年12月1日木曜日

対話的にデプロイを行うシェルを書いた。

サーバ側にある対話型デプロイツールを使うとき、
いちいちサーバにsshするのがめんどくさいので、
シェルを書いてみた。

expectコマンドの使い方

対話型アプリケーションを自動実行する
対話型のコマンドを自動化できるexpectコマンド
[expect] spawnしたプロセスの終了ステータスを得る


① 対話型リモートデプロイシェル
まず、expectをインストール(apt-get install expect)
deploy() {
    #--- for backspace  
    stty intr ^\?
    stty erase ^H

    #--- get parameter  
    DEPLOY_ENV=$1

    #--- confirm commit  
    if [ "${DEPLOY_ENV:-null}" = "null" ]; then
        echo
        echo "deploy type"
        echo "type :  tst # kg_tsubasa.dev.klabgames.net"
        echo "        stg # kg_tsubasa.klabgames.net"
        echo
        return

    elif [ $DEPLOY_ENV = 'tst' ]; then
        DEPLOY_SERVER="tsubasa.dev.klabgames.net"

    elif [ $DEPLOY_ENV = 'stg' ]; then
        DEPLOY_SERVER="tsubasa.klabgames.net"

    else
        echo
        echo "deploy type"
        echo "type :  tst # kg_tsubasa.dev.klabgames.net"
        echo "        stg # kg_tsubasa.klabgames.net"
        echo
        return
    fi
    #--- which deploy  
    echo
    echo -n "Which Deploy (site:s / mgr:m) > "
    read FLG_DEPLOY_TYPE

    if [ "${FLG_DEPLOY_TYPE:-null}" = "s" ]; then
        DEPLOY_TYPE="site"
    elif [ "${FLG_DEPLOY_TYPE:-null}" = "m" ]; then
        DEPLOY_TYPE="mgr"
    else
        echo
        echo "Please Input s or m."
        echo
        return
    fi

    #--- confirm deploy  
    echo
    echo -n "Deploy on $DEPLOY_SERVER of $DEPLOY_TYPE ? (y/n) > "
    read FLG_DEPLOY

    if [ "${FLG_DEPLOY:-null}" = "y" ]; then
        echo ""
    elif [ "${FLG_DEPLOY:-null}" = "n" ]; then
        echo
        echo "Thank you."
        echo
        return
    else
        echo
        echo "Please Input y or n."
        echo
        return
    fi

    #--- confirm commit  
    SSH_AGENT_PS=`ps -e | grep ssh-agent`
    echo $SSH_AGENT_PS
    if [ "${SSH_AGENT_PS:+exist}" = "exist" ]; then
        expect -c "
            set timeout 1
            spawn ssh -l kg_tsubasa $DEPLOY_SERVER 
            expect \"kg_tsubasa@w112:~$ \" 
            send \"deploy -s $DEPLOY_TYPE \n\"
            expect \"Deploy OK?\"
            send \"n\n\"
            send \"exit\n\"
            interact
        "
    elif [ "${SSH_AGENT_PS:-nonexist}" = "nonexist" ]; then
        expect -c "
            set timeout 1
            spawn ssh -l kg_tsubasa $DEPLOY_SERVER
            expect \"Enter passphrase for key '/home/karino/.ssh/id_rsa':\" {
                send \"password\n\"
            }
            expect \"kg_tsubasa@w112:~$ \"
            send \"deploy -s $DEPLOY_TYPE \n\"
            expect \"Deploy OK?\"
            send \"n\n\"
            send \"exit\n\"
            interact
        "
    fi
    echo

ssh-agentが立ち上がっているか否かによって、
条件分岐をしているが、
もう少しうまいやり方がありそうな気がする。

そして、正常終了したか否かのステータスはつけていない・・・。

ssh回りの設定をした時のめも。

【ssh パスワードと公開鍵認証の違い】
sshについて


【ssh RSAとDSAの違い】
SSHでの暗号方式、RSAとDSAの違い


【ssh鍵の生成】
$ ssh-keygen -t rsa
$ cat id_rsa.pub >> $HOME/.ssh/authorized_keys
ssh-keygenによって生成されるファイルが2つ。
id_rsa :秘密鍵
id_rsa.pub :公開鍵

公開鍵のほうを接続先のサーバに設定。


【sshパスフレーズ入力省略】
ssh-agent
① bashrcとかに書く。
$ eval `ssh-agent`
$ ssh-add ~/.ssh/id_rsa

※ これだと、ssh接続ごとにパスワードを入力する必要がある。

② keychainを使う。
keychain
「.bash_profile」に下記を書く。
keychain .ssh/id_dsa
. .ssh-agent-${HOSTNAME}


【sshfs】
① パスフレーズ
マウント:$ sshfs karino@server: /home/karino/@server
アンマウント:$ fusermount -u /home/karino/@server

② 公開鍵認証の場合
マウント:$ sshfs -o IdentityFile=/home/karino/.ssh/id_rsa karino@server: /home/karino/@server
アンマウント:$ fusermount -u /home/karino/@server


【sshのkeepalive】
/etc/ssh/ssh_configに、
ServerAliveInterval 120と書く。
これは、120秒毎に、ssh接続先にkeepaliveを飛ばす設定。

2011年11月30日水曜日

tf-idfを実装した結果

【これまでの流れ】
① はてぶのようなサイトから持ってきた文書群と
任意の文書を比較して、似ているものをランク付けする
プログラムを書いている。

② 大まかな流れは、文書群から単語を抽出し、
  それを変数とした特徴ベクトルを文書毎に作成する。
  そして、比較したい文書の特徴ベクトル間のコサインをとり、
文書間の関連性とする。

③ この文書比較の精度を上げるため、
  tf-idfを使って文書毎に重要な単語を抽出し、
  特徴ベクトルの変数としてみる。


【今回やったこと】
今回、tfidfを実装してみたので、以下を載せる。
① tfidfによって抽出される重要単語の確認。
② tfidfを利用した場合としなかった場合の文書比較結果

※ 対象にした文書群
lifehackerの記事 : 15件
スゴレンの記事 : 11件
「原子力」って調べたときの検索結果 : 10件

※ ちなみに抽出された単語のフィルタリングは、
高い順にソートし累積値が全体の35%になった時点で切り捨てた。



【tfidfによって抽出される重要単語の確認】
まずは、この記事。
風知草:曲がり角からどこへ?

抽出された重要そうな単語はこれ。
0.17808383571585        もんじゅ
0.10330111288117        政策
0.084143345761451       原発
0.076321643878219       細野
0.06351958877225        円
0.050881095918813       現実
0.050881095918813       仕分け人
0.050881095918813       首相
0.050881095918813       表面
0.050881095918813       抜本
0.050881095918813       トン
0.050881095918813       核のゴミ
0.050881095918813       ムダ
0.050881095918813       使用済み燃料
0.050881095918813       曲がり角
0.043022928448548       基本

うん。確かにそれっぽい単語をとってきている。

つぎはこれ。
女の子の「あなたに興味がない!」という遠回しなNGサイン9パターン

抽出された重要そうな単語はこれ。
0.21558386420146        ナシ
0.21558386420146        脈
0.20183899990487        女の子
0.10091949995243        興味
0.094058059817577       女性

わかりやすいw。
そして前の例と比べて、計算されたtfidf値が高い。
つまり、
文書を見てみると、「脈ナシ」って単語が10個あった。
1つ目の記事に「もんじゅ」は10個。
つまり、ほかの文書に「脈ナシ」って単語が少なかったため、
重要だと判断されたと。
あと、単語が分割されてしまった。mecab辞書をもっとよくしなきゃ。


最後はこの記事。
寝る前の飲酒を控えて、いびきをストップ!?

抽出された重要そうな単語はこれ。

0.34947279038974        いびき
0.11649093012991        びき
0.054531940325175       酒
0.054531940325175       空気
0.038830310043305       適切
0.038830310043305       生理学
0.038830310043305       身体
0.038830310043305       通り道
0.038830310043305       睡眠時無呼吸症候群
0.038830310043305       医療機関
0.038830310043305       症状
0.038830310043305       医学
0.038830310043305       空気抵抗

いびきのtfidf値が高い。
記事を見ると「いびき」という単語が27個出てきている。
このせいか。




【tfidfを利用した場合としなかった場合の文書比較結果】
抽出した重要単語を変数とした特徴ベクトルを作成し、
記事と似た文章を、文書群のなかから抽出してみる。
コサインが0.7以上のものを抽出。
比較対象として、tfidfを利用しない場合も載せる。

まずは、この記事。
風知草:曲がり角からどこへ?

(1) tfidfを利用しない場合。
0.92011443      東芝が原発機器輸出へ、米34年ぶり原発新設再開 | Reuters
0.90298215      契約更新しない!第1原発1月に保険切れ - 経済ニュース : nikkansports.com
0.87446821      原子力防災など強化分野 エネ研拠点化会議で確認 福井・敦賀 - MSN産経ニュース
0.74048286      原子力は重要な電源=橋下氏の原発縮小路線に―関電社長 - WSJ日本版 - jp.WSJ.com
(2) tfidfを利用した場合。
0.9941724       原子力は重要な電源=橋下氏の原発縮小路線に―関電社長 - WSJ日本版 - jp.WSJ.com
0.98811356      原子力安全高度化へ技術開発を JEMA会長が必要強調 - 産業・技術 - ニュース - 電気新聞
0.9902511       契約更新しない!第1原発1月に保険切れ - 経済ニュース : nikkansports.com
0.9833529       外部電源で2回線以上 原子力安全委が喪失対策 - MSN産経ニュース
0.97699438      原子力防災など強化分野 エネ研拠点化会議で確認 福井・敦賀 - MSN産経ニュース
0.96333347      東芝が原発機器輸出へ、米34年ぶり原発新設再開 | Reuters

どちらも似通った記事をとってきていることがわかるが、
tfidfを利用した場合のほうが、コサインが顕著に分かれている。


もうひとつ、この記事。
女の子の「あなたに興味がない!」という遠回しなNGサイン9パターン

(1) tfidfを利用しない場合。(0.7以上が全然なかったので、0.1以上を表示)
0.67150338      「これを始めたらモテ出した」というモテる男の行動習慣9パターン|スゴレン
0.3456989       クリスマス当日に、滑り込みで女の子を誘う口実9パターン|スゴレン
0.23763611      女性が「ひそかに自信をもっている個性」をさりげなく褒める一言9パターン|スゴレン
0.15194308      「私に告白してよ!」という裏メッセージが含まれている女性のセリフ9パターン|スゴレン
0.14351136      女性がグラッとくる男性のスペック9パターン|スゴレン

(2) tfidfを利用した場合。
0.76842209      「これを始めたらモテ出した」というモテる男の行動習慣9パターン|スゴレン
0.43482185      クリスマス当日に、滑り込みで女の子を誘う口実9パターン|スゴレン
0.30439966      [Androidアプリレビュー]子どもの成長記録に便利!?(浮気の追及にも!?) 寝言を録音できる『NEGOTO Recorder』 #TABROID
0.27703564      女性が「ひそかに自信をもっている個性」をさりげなく褒める一言9パターン|スゴレン
0.27239949      失敗した時は、うまくいく方法を見つける過程だと考えよう [gReader]
0.20112109      「私に告白してよ!」という裏メッセージが含まれている女性のセリフ9パターン|スゴレン
0.18463171      女性がグラッとくる男性のスペック9パターン|スゴレン

意外にコサインの値が低くなる。
特徴ベクトルの変数を「重要単語」に絞ったため、
近い変数が少なくなったのかな。
なんで、Androidアプリレビューが入ってるんだw。


ついでにこの記事も。
寝る前の飲酒を控えて、いびきをストップ!?

(1) tfidfを利用しない場合。
0.91099372      コワーキングを楽しむ3つのススメ [gReader]
0.90791908      [Androidアプリレビュー]子どもの成長記録に便利!?(浮気の追及にも!?) 寝言を録音できる『NEGOTO Recorder』 #TABROID
0.89963271      聞いている音楽にぴったりのカクテルレシピを教えてくれる新感覚サイト「Drinkify」 [gReader]
0.85027147      失敗した時は、うまくいく方法を見つける過程だと考えよう [gReader]
0.83635293      90分の「集中タイム」と30分の「完全な休憩」を交互に取る生産性向上メソッド [gReader]
0.78096475      不眠症を回避するための一日の過ごし方
0.72454513      ソーシャルゲームがパチンコよりも優れている理由 - ぼくはまちちゃん!(Hatena) [gReader]

(2) tfidfを利用した場合。
0.94035399      コワーキングを楽しむ3つのススメ [gReader]
0.81401848      プログラマーは"一線"を超えると急激に伸びる - Linux/Ruby 小崎氏(後編) | エンタープライズ | マイナビニュース [gReader]

いまいちつながりがわからん。



【思ったこと】
1、重要単語に絞ったため、特徴ベクトルが一致しにくくなった。
コサインの値が高くなるかどうかは、特徴ベクトルの変数がどれだけ近くなるかによる。
つまり、同じ単語が一切なければ、
ゴミ単語が多いと精度は下がる。しかし特徴を表す単語が少なくても精度は下がる。

より文書の特徴をうまく反映した単語を抽出するために。

① mecab辞書
やっぱりゴミみたいな単語まで含まれている。
mecab辞書の見直しと抽出する品詞を限定しよう。

② ifidfの重要単語の基準値
tfidf値から重要単語を判断する基準値はどうしよう?
今回適用に全体の35%としたが。

③ 別の重要単語の抽出方法
統計情報に基づき重要語を抽出もやってみたい。

④ 単語間の意味的つながり
単語どうしの意味的なつながりを加味する。

(1) 単語同士の意味的なつながりを表すデータを準備しておいて、
重みづけをする際、それを加味する。
全然やり方検討つかんけど。
論文探してみよう。

(2) 特異値分解をしているから、
2つの文書間に直接共通する単語がなくても、
それらをつなぐ文章があれば意味的なつながりは加味されるはず。

じゃ、抽出したい文書群に加え、
単語同士の意味的なつながりを表す文書群を加えては?。


2、文章群の範囲をもうすこし考えよう。
「原子力」や「スゴレン」のようにテーマがはっきり決まっているものは、
うまく抽出できるが、「ライフハッカー」のように1つ1つの記事のテーマがばらばらだと
うまく抽出できてない。文書の範囲を狭くしたほうがいいのかな。
でも逆に、「母数がすくないから、似たような記事がなかった」とも考えられる。
それに、文書の範囲を狭めると文書の差異が細かくなって、区別するのが難しいかも。
要検討。


3、もう少し定量的に結果を比較する方法がほしいな。

2011年11月25日金曜日

bzr の処理中にエラーが発生しました。

apt-get installを実行したとき、
「 bzr の処理中にエラーが発生しました」と出た。


① エラーの内容確認

dpkg: bzr の処理中にエラーが発生しました (--configure):
 サブプロセス インストール済みの post-installation スクリプト はエラー終了ステータス 1 を返しました
configured to not write apport reports
                                      dpkg: 依存関係の問題により bzrtools の設定ができません:
 bzrtools は以下に依存 (depends) します: bzr (>= 2.1~) ...しかし:
  パッケージ bzr はまだ設定されていません。
 bzrtools は以下に依存 (depends) します: bzr (<= 2.2) ...しかし:
  パッケージ bzr はまだ設定されていません。
dpkg: bzrtools の処理中にエラーが発生しました (--configure):
 依存関係の問題 - 設定を見送ります
liberror-perl (0.17-1) を設定しています ...
configured to not write apport reports
                                      git (1:1.7.2.5-3) を設定しています ...
以下のパッケージの処理中にエラーが発生しました:
 bzr
 bzrtools
bzrの処理ってなんだろう。。 その前に、not foundってエラーがいっぱい出てる。
・・・
   dpkg: /usr/lib/python2.5/site-packages/bzrlib/xml4.py not found.
   dpkg: /usr/lib/python2.5/site-packages/bzrlib/xml5.py not found.
   dpkg: /usr/lib/python2.5/site-packages/bzrlib/xml6.py not found.
   dpkg: /usr/lib/python2.5/site-packages/bzrlib/xml7.py not found.
   dpkg: /usr/lib/python2.5/site-packages/bzrlib/xml8.py not found.
   dpkg: /usr/lib/python2.5/site-packages/bzrlib/xml_serializer.py not found.
② pythonの再インストール python2.5、入ってないんじゃないかな。 そんなこともない。 /usr/lib/python2.5/site-packages/bzrlib/ ~ がないんじゃないかな。 そんなこともない。 ③ bzr再インストール
$ apt-get remove bzr
$ apt-get install bzr

治った。
bzrがちゃんとインストールされていなかっただけかな。

やっぱりべたにtf-idfでやろうかな。

語の共起の統計情報に基づく文書からのキーワード抽出アルゴリズム
を読んだ。

精度としては、tf-idfと同じくらいのものらしい。
違いとしては、tf-idfでは比較対象となる文章群が必要になること。
この論文の方法では、比較対象が必要ない。

なんか重みづけとの区別なくなってきたが。
この辺とか役に立ちそう。
TFIDFを使ってwikipediaの各キーワードの特徴量を抽出
形態素解析と検索APIとTF-IDFでキーワード抽出


基本的なtf-idfの式で計算できる。

tf : 対象となる文書中の単語出現数 / 文書の総単語数
N :全てのドキュメント数
df :代表キーワード候補が含まれるドキュメントの数 (DF)、

・tfの意味は、文章中の対象の単語がいっぱい出てくれば、
その単語は重要とみなすということ。
・log~の意味は、対象の単語が他の文章になければ、
その単語の重要度を上げようということ。

つまり、得られたwの値が高いほど、N個の文書群の中で、
重要な単語であると考えられる。

※ tfの取り方はいくつかやり方が見つかったが、
文章の長さを考慮したこのやり方がいいと思った。
(長い文書ほど、重要語が出やすいだろうということ)



ということで、特徴ベクトルの変数の取り出し方
① tf-idfで重要語を抽出、それを特徴ベクトルの変数とする。
② 統計情報に基づき重要語を抽出、それを特徴ベクトルの変数とする。

どっちがいいんだろう。
わかりやすいtf-idfのほうからやってみるか。

2011年11月24日木曜日

文章の長さが特徴ベクトルに与える影響の軽減 ~背景~

はてぶのようなサイトからテキストデータを持ってきて、
任意の文章と似ているものをランク付けするプログラムを書いてみた。
が、精度がいまいち。

文章の類似性を測る方法として、
いくつかの論文を読んで使われていた、
以下の方法を使っている。
形態素解析で文章中の単語を抽出。
その単語を変数とした特徴ベクトルを作成し、
測りたい2つの文章の特徴ベクトル間のコサインをとって
2つの文章の類似性とする。

検討しなければならないポイントは次の2つ。

① 比較したい文章の特徴をうまく特徴ベクトルに反映させるため、
特徴ベクトルの変数を何にするか検討する。

② さらに、文章の特徴をより強く反映させるため、
特徴ベクトルの重みづけをする。


今現在、精度に大きな影響を与えているのは、
①の特徴ベクトルの変数の選び方だと思う。
だって、はてぶからとった文章の名詞を全部、
特徴ベクトルの変数にしてるんだから。

つまり、同じ内容の文章でも、その文章の長さによって、
特徴ベクトルが変わってしまう。
これはいまいちいけてない。

で、調べてみたら、以下の論文が目に付いた。
語の共起の統計情報に基づく文書からのキーワード抽出アルゴリズム

まだちゃんと読んでないが、
「単語Aの文章中における出現確率」と
「単語Bが含まれる文中に、単語Aが出現する確率」とを比較し、
偏りが見られれば、単語Aと単語Bの意味的なつながりが
大きいと判断できるというもの。


これを使えば、ある1つの文章の中で重要な単語を、
ほかの文章と関係なく抽出することができる。
そうやって抽出した単語を特徴ベクトルの変数として使えば、
文章をその内容的に近いものを抽出できるようになるのでは?
ちょっと作ってみよう。

2011年11月20日日曜日

河野君が作ったReadItLater.phpを使ってみる。

1、Zend frameworkのインストール
ここに書いてある感じで。
Programer's Reference Guide

Zend Frameworkのダウンロード
アカウントを作る必要がある。

②phpのincludeパスにを通す。
; Zend Framework 
include_path = "/usr/local/share/ZendFramework-1.11.11/library"



2、ReadItLater.phpをダウンロード
$ git clone git://github.com/aoiaoi/ReadItLater.git


また、ReadItLaterのAPIについては
API Documentationを参照。


3、自分のRILからリストを取得する。
get();
    $response_body = $response->getBody();

    // 
    $jobj = json_decode($response_body);  
    foreach($jobj->list as $item){
        echo "title : " . $item->title . "\r\n";
        echo "url   : " . $item->url   . "\r\n";
    }
?>

参考
戻りリストの取得


4、テキストの取得
text($url,$text_options);
    $text_response_body = decUnicode($text_response->getBody(),"UTF-8");   

?>

RILから返ってくるレスポンスはUnicodeで書かれているため、
UTF8に変換する必要がある(最後の行)。
Unicode変換ツール(PHP編)
これで行くか。

URLによっては、テキストを取得できない場合があった。。

2011年11月18日金曜日

read it laterに関する設定

Read It Laterを使おうと思った。
とりあえず設定できそうなことをいろいろ設定してみた。
全部使うかは怪しいが。。

ひとつの使い方として参考になる


1、アカウントを作成
こんな感じ


2、ブックマークレットの追加
ここからとる


3、google readerの送信先を追加する
やり方
画面右上の[設定]→[リーダー設定]→[Send To(送信先)]→[Create a custom link(カスタムリンクを作成)]

① APIキーの取得
まず、APIきーを取得

② Read It Later
Name:RIL
URL:https://readitlaterlist.com/edit?username=<ユーザー名>&password=<パスワード>&apikey=<API KEY>&url=${url}&title=${title}
Icon URL:http://readitlaterlist.com/favicon.ico

③ ついでにはてブを設定
Name:はてブ
URL:http://b.hatena.ne.jp/add?mode=confirm&title=${title}&url=${url}
Icon URL:http://b.hatena.ne.jp/images/append.gif


4、Galaxyからgoogle reader読んでるときは。
gReaderを使えば、ReaditLaterにポストできる。


5、GalaxyからRead It Laterを読むときは。
Read It Laterのアプリ使う。


今度、evernoteの使い方も見直そう。

2011年11月17日木曜日

phpでCARTアルゴリズムを使った決定木を作成する。

PHPで,CARTアルゴリズムを使った決定木の作成をやってみた。
CARTアルゴリズムは、こんなかんじ

とりあえず、
①ある変数で2つに分類したノードそれぞれで、目的変数に対するジニ係数を計算する。
②ルートノードのジニ係数と、分類したノードのジニ係数の差を計算する。
③すべての変数に対して、その差を計算し、差が最大のものを分岐条件とする。
④これを繰り返していく。
こんな感じで。


1、渡すデータ
必要なデータを入れた配列を、さらに配列に入れた形。
// 渡すデータ構造
    $data = array();
    $data[0]  = array("生死"=>"生還","年齢"=>"35","性別"=>"男","等級"=>"1等");
    $data[1]  = array("生死"=>"生還","年齢"=>"12","性別"=>"女","等級"=>"1等");
    $data[2]  = array("生死"=>"生還","年齢"=>"35","性別"=>"女","等級"=>"2等");
    $data[3]  = array("生死"=>"死亡","年齢"=>"34","性別"=>"女","等級"=>"2等");
    $data[4]  = array("生死"=>"生還","年齢"=>"23","性別"=>"男","等級"=>"3等");
    $data[5]  = array("生死"=>"死亡","年齢"=>"31","性別"=>"男","等級"=>"3等");
    $data[6]  = array("生死"=>"死亡","年齢"=>"32","性別"=>"男","等級"=>"3等");
    $data[7]  = array("生死"=>"死亡","年齢"=>"23","性別"=>"男","等級"=>"乗組員");
    $data[8]  = array("生死"=>"死亡","年齢"=>"25","性別"=>"男","等級"=>"乗組員");
    $data[9]  = array("生死"=>"死亡","年齢"=>"29","性別"=>"女","等級"=>"乗組員");
    $data[10] = array("生死"=>"死亡","年齢"=>"40","性別"=>"女","等級"=>"乗組員");
データ : 船が難破したときの乗客の生還死亡リスト
目的変数 : 生死
カテゴリ変数 : 年齢、性別、等級



2、多値変数、連続変数をすべて、二値変数に変換する
決定木は二分木なので、
持っている変数の中で値が3種類以上あるもの(多値変数:等級)、
値が連続であるもの(連続変数:年齢)を、
二値変数に置きなおす必要がある。

① 多値変数を二値変数に変換する
多値変数の取りうる値を2つのグループに分け、
二値変数とする。
この時も、CARTアルゴリズムを使い、
どの分け方が、もっとも目的変数の影響を反映するかを
確定する。

多値変数「等級」が、以下の感じの二値変数となる。
グループ1 : 1等
グループ2 : 2等3等乗務員


② 連続変数を二値変数に変換する
連続変数の値が昇順になるよう並び替え、
どこで区切るともっとも目的変数の影響を反映するかを、
またCARTアルゴリズムを使って確定する。

連続変数「年齢」が、以下の感じの二値変数となる。
グループ1 : 30 以下
グループ2 : 30 より大きい



3、木の生成

① 分岐
CART使って分岐条件になる変数を決め、データを分ける。
そのデータでさらに分岐条件を決め、またデータを分ける。
これを繰り返して、木構造を作成する。


② 分岐の終了、枝刈り
なんかいろいろ方法あるみたいだけど、
とりあえず、最後までやればいいや。



4、木の利用
入力したデータから目的変数を除いた形式で配列を渡すと、
想定される目的変数の値を返すようにした。

// 渡すデータ構造
    $target = array("年齢"=>"40","性別"=>"女","等級"=>"乗組員");



なんとなくできたが、
なんちゃってデータマイニングになっている感は
否めない。

拙いコードだけどさらしてみる。

https://github.com/kokukuma/php-decision-tree

2011年11月16日水曜日

重複しない数字を2つのグループに分割する。

全組み合わせを抽出したあと、
重複しているものを取り除く形で作った。
一方のグループを要素の配列として出力。

長すぎる。
絶対もっときれいな書き方あると思う。


 $value) {
        echo implode($value)."\n";
        //echo var_dump($value);
        //echo "--------------\n";
    }

    function split_data($data)
    {
        $result = array();
        $return = array();

        // 組み合わせを抽出 
        for ($i=0; $i < count($data)-1; $i++) {
            $res = conbination($data , $i+1);
            foreach ($res as $key => $value) {
                array_push($result,$value);
            }
        }

        // 重複を排除
        $length = floor( count($data) / 2);
        $flg    = count($data) % 2;

        foreach ($result as $key => $value) {
            if(count($value) <= $length){
                switch ($flg) {
                case 0:
                    $max = max($data);
                    if(!array_search($max, $value)){
                        array_push($return,$value);
                    }
                    break;
                case 1:
                    array_push($return,$value);
                    break;
                }
            }
        }
        return $return;
    }

    function conbination($array,$num)
    {
        $arrnum = count($array);
        if($arrnum < $num){
            return;
        }else if ($num==1) {
            for ($i=0; $i < $arrnum; $i++) {
                $arrs[$i] = array($array[$i]);
            }
        }elseif ($num>1) {
            $j=0;
            for ($i=0; $i < $arrnum-$num+1; $i++) {
                $ts = conbination(array_slice($array,$i+1),$num-1);
                foreach ($ts as $t ) {
                    array_unshift($t,$array[$i]);
                    $arrs[$j]= $t;
                    $j++;
                }
            }
        }
        return $arrs;
    }
?>

2011年11月13日日曜日

Rで決定木を作成する。

Rで決定木を作成してみる。

1、mvpartをインストール.
$ sudo wget http://cran.r-project.org/src/contrib/mvpart_1.4-0.tar.gz
$ sudo tar -xvzf mvpart_1.4-0
$ sudo R
> install.packages("mvpart_1.4-0.tar.gz",destdir=".",repos=NULL)
> library(mvpart)


2、木の基本
① 「read.csv」でデータ読み込んで、「rpart」で木を作る。
② 木には、分類木と回帰木がある。
  分類木は分類、回帰木は数値を返す。
③ 「cp (complexity parameter)」で木の複雑さを表す。
  mvpartのデフォルトでは、CP=0.01
  CPが高いほど、木は単純になるが誤差が大きくなる。
  小さいほど、木は複雑になるが誤差は小さくなる。
  で、誤差が十分小さく、単純な木がほしい。
  最適なCPを図る方法も必要。


3、mvpartを使って、木を作ってみる。
① 偽札のCSVデータ(真偽、下部マージンの長さ、対角線の長さ、)
> nd <- read.csv("nisesatsu.csv",header=T)
> nt <- rpart(真偽~. , data=nd,type="class")
> print(ht)

② 不動産価格のCSVデータ(価格、犯罪率、部屋数、築年数、等)
> hd <- read.csv("house.csv",header=T)
> ht <- rpart(真偽~. , data=hd,type="anova")
> print(ht)

③ 不動産価格のCSVデータ、CP変更
> hd <- read.csv("house.csv",header=T)
> ht <- rpart(真偽~. , data=hd,type="anova", cp=0)
> print(ht)
> ht2 <- prune(ht, cp=0.03)
> print(ht2)

2011年11月11日金曜日

ソーシャルグラフに関する論文を読んだときのメモ

ソーシャルグラフについての論文を読んだメモ。

グラフデータを使い、ユーザの特徴をどう表現すればいいかが知りたくて調べてみた。ぶっちゃけそれは最初の論文だけで、後はソーシャルグラフの応用例的な。なんか長くなったので、読んだ論文のリストを書く。

1、ソーシャルネットワークにおけるリンク構造を用いた重複クラスタリング手法の提
2、MAKOTO:ソーシャルグラフを用いたコミュニケーション支援システムの提案
3、Twitter Catches the Flu: 事実性判定を用いたインフルエンザ流行予測
4、目的地にいる人々とのコミュニケーションを促進するシステムの開発



1、ソーシャルネットワークにおけるリンク構造を用いた重複クラスタリング手法の提
「プロフィール」からだけでなく、
「リンク」からもユーザの特徴を抽出し、
複数のクラスタに所属させようという研究。
「プロフィール」ではなく、「発言」だけど、
プロフィールのほうがイメージしやすかったので、
そっちで書く。


この研究では、
そのユーザが受けている「リンク」は、「リンク元ユーザの関心」を表し、
「リンク元ユーザの関心はリンク先ユーザ(対象ユーザ)の特徴を表す」
と考える。

そのため、対象ユーザの特徴を、
対象ユーザの「プロフィール」から抽出される特徴と、
対象ユーザの「リンク元ユーザとかのプロフィール」から抽出される特徴の
2種類からなる。(どちらもプロフィールを基に定義した特徴ベクトルなので、
その評価軸は同じにできる)

そのため、対象ユーザの特徴ベクトルは、
1+リンク数だけ持つことになり、
最大で、その数だけ別のクラスタに所属することになる。

さらに、リンク元ユーザが「どんな関心」をもって対象ユーザに
リンクをしているのかを定義づける必要がある。
それには、リンク元ユーザと対象ユーザが、
「共通している持っているリンク先の特徴」を使う。
これに重みづけをして、
1つの対象ユーザの特徴ベクトルを作成する。


なんかややこしい。
リンクの特徴をリンク元ユーザとかのプロフィールを使って、
表現するのは面白いと思った。


2、MAKOTO:ソーシャルグラフを用いたコミュニケーション支援システムの提案
とりあえず、写真見るだけでも一見の価値があると思う。
やっていることは、twitterから自分のついーと引っ張ってきて、
単語抽出して、ほかの人のそれと比較しているだけ。
でも、その利用方法、見せ方がすごく面白い。


3、Twitter Catches the Flu: 事実性判定を用いたインフルエンザ流行予測
タイトルまんま。twitterの発言内容からインフルエンザの流行を予測しようって研究。
同じようにインフルエンザを予測しようという研究は多くあるみたい。
「医療アドバイスコールセンターへの問い合わせ数」、「インフルエンザ市販薬の販売量、
「インフルエンザに関するGoogleの検索クエリ数」。
この研究では、「インフルエンザにかかっていると思われるツイート数」

この際問題になるのが、「発言者がインフルエンザにかかっているかどうか」を
どうやって判断するか。インフルエンザを含むツイートすべての集計では、
「インフルエンザじゃなかったw」といった発言までカウントしてしまう。
それを判別するために使われているのが、サポートベクターマシン(SVM)。

サポートベクターマシンは、
ニューラルネットワークの一種だとか。
詳しいとこまで理解できてないが、
要は、決定木と同じように、入出力のルールを
抽出するものだと思う。

この研究では、あらかじめ、
ツイート内容とインフルエンザ陰性・陽性のセットを準備して、
(人がツイート内容を読んで判断)
SVMにより、インフルエンザという単語の周辺の単語から、
発言者やその周辺の人がインフルエンザにかかっているかどうかを判断する
ルールを抽出する。

この結果、google flu trendと同じくらいの精度が出たとか。。
ただし、加熱報道時には大きく精度が悪くなるとか。
twitterっぽいw。

同じように、twitterを使った地震予知とかもある。
Earthquake Shakes Twitter Users:
Real-time Event Detection by Social Sensors




4、目的地にいる人々とのコミュニケーションを促進するシステムの開発
こっちが作りたいと思っていたものとよく似ている。
「知っている人にメッセージを送る」という意味で。
ここでは、質問内容を場所に関するものに限定し、
(情報を知っている人)=(その場所にいる人)としている。
さらにメッセージを送るための仕組みとして、
自分らでtwitterクライアントを作成することで何とかしようとしてる。
やはり問題は、「質問内容を知っている人の絞り込み」と
「メッセージ送信方法」か。

2011年11月10日木曜日

決定木に関する論文を読んだ時のメモ

決定木の応用方法について調べた。

1、系列パターンを利用した決定木による自然言語における選択ルール獲得
ある文章中に「結構」という単語が出てきたとき、
それがどんな意味で使われているか
(論文中では、「かまわない」、「いらない」、「すばらしい」の3つ)を、
前後に現れる単語によって判断するためのルールを抽出する研究。

ルールの抽出には、決定木を利用する。
決定木とは、入力と出力の組み合わせを計算するもの。
入力が「AかつB」なら、出力は「X」
入力が「AかつBかつC」なら、出力は「Y」
みたいな選択ルールを抽出してくれる。

この論文では、前後に現れる単語の出現する順序の組み合わせを、
決定木の入力とし、系列パターンと呼んでいる(PrefixSpanというアルゴリズムで抽出)。
さらにこれを単語そのものだけでなく、単語の読み,原形,品詞,活用,型、
それぞれにおいて、系列パターンを抽出し、決定木の入力とする。
この結果、「結構の意味を分類する選択ルール」を決めることができる。

この選択ルールを使えば、「結構」を含む任意の文章から、
どの意味でつかわれているかを機械的に判断することができる。

この論文ではさらに、「話しているのが男か女かを判断するルール」を抽出している。
この決定木の入力には、文章の終助詞、代名詞を利用している。


2、決定木分析による都市型アミューズメント施設の来訪者特性評価
決定木の説明がよくされている。
この論文でやっているのは、
「どんな人がラーメンスタジアムに来るかを判断するルール」を作成している。
決定木の入力としては、過去に来訪した人の特徴を使っている。
具体的には、性別、年齢、職業、自宅からの距離などを使う。



3、決定木とQM法による職業意思決定過程分析
学生のうち「どんな人が自分の職業を決められているかのルール」を作成している。
決定木の入力には、学生の心理的状態を使っている。
これは、学生からとったアンケートを基に、
「未熟」、「混乱」、「猶予」、「模索」、「安直」と、
職業を決める際にありそうな心理的状態を数値化して利用している。


4、そのほか読んでないが。。
・健康維持のための室内温熱環境制御法の一提案
・データマイニングの手法を用いた定期歯科受診者の受診中断に関わる要因の分析
・ネットオークションの商品情報を用いた決定木学習による出品者の行動パターンの分類

すげー面白そうw。
つまり決定木を使ってできることは、
「経験的に因果関係のありそうな事柄を、定量的に評価する」ことか。
そういった意味では、ニューラルネットワークと近しいものを感じる。

2011年11月8日火曜日

PHPで潜在的意味解析

芸能人の相関関係を探ってみる。

redsvdのチュートリアル

誰かの論文

単語と意味属性との共起に基づく概念ベクトル生成手法


これをニュースの記事でやってみる。
基本的に、PHPを使う。


1、ニュースのタイトルと本文を取得
① phpの関数simplexml_load_fileで、rssからタイトルとかURLとか取得できる。
PHPでRSSを読み込む方法

② 下記のサービスをつかえば、全文配信にしてくれる。
http://fulltextrssfeed.com/
※ 本文はdescriptionタグに入れられる。

余計なタグは、「strip_tags」という関数で除去することができる。



2、共起行列の作成

① mecabを使い、本文からキーワードを抽出。
しかし、でふぉの辞書ではいまいち。下記をやってみる。
mecabのユーザ辞書でwikipediaとhatenaキーワードを利用する
辞書の場所 : /usr/local/lib/mecab/dic/ipadic
使う辞書の設定 : /usr/local/etc/mecabrc


② RMecabを使う。

(1)CentOS5.5で、yumでRをインストール
※1 urlは「http://rm.mirror.garr.it/mirrors/CRAN/bin/linux/redhat/el5/x86_64/」二変更
※2 「libtcl」「libtk」を入れる。
※3 どうやら「R-core2.0」は最新ではないらしい。
rpmforgeをいれ、yum listすると「R-core2.3」がインストールできた。

(2)RMecabをインストールする。
※1 tar.gzは、R-2.13.0用からダウンロードする。
※2 wgetでダウンロードできなかったから、別マシンで落として、winscpで送った。
$ sudo tar -xvzf RMeCab_0.95.tar.gz
$ sudo R
> install.packages("RMeCab_0.95.tar.gz", destdir=".", repos=NULL)
> library(RMeCab)    ↓(3)を忘れるとエラーが出る。


(3)libmecab.so.1: 共有オブジェクトファイルを開けません
※1 /etc/ld.so.conf.d/mecab.conf を作成。
※2 /usr/local/libのままでよい。
※3 $ sudo /sbin/ldconfig を実行。


(4)RMeCabを使う。

$ R
> library(RMeCab)
> RMeCabC("すもももももももものうち")
> res <- docMatrix("doc", pos = c("名詞", "形容詞", "助詞"), weight = "tf*idf")
> res
> q()


③ phpで書く。
RMeCabをPHPから使うのはめんどくさそうだったので、
PHPで直接書いた。
行に文章、列に抽出した全語句を割り当て、
共起行列を作成した。



2、特異値分解処理(次元圧縮)
PHPで行列の計算をするのはめんどくさそう。
考えた選択肢としては、

① PHP行列計算ライブラリを使う。

見つからないかった。


② redsvdを使い、行列計算用 PHP Extensionを作成する。
redsvdを使うためには、eigen3をインストールする必要がある。
また、c++なので、Extensionを作成し、PHPから使えるようにする必要がある。
つまり、作ろうとしている潜在意味解析モジュールを使おうとしたら、
Extensionのいんすとーる、eigen3のいんすとーる、redsvdのいんすとーるを
する必要がある。
ちょっとめんどい。

③ eigen3を使い、行列計算用 PHP Extensionを作成する。
redsvdを使わなくても、eigen3だけでも特異値分解は可能。
これなら、
Extensionのいんすとーる、eigen3のいんすとーる、だけでよい。
まだまし。
そのためには、

・ eigen3の使い方調べる。
・ C++でphp extensinoを作る方法の調査
・ PHP extensionで、配列を受け渡す方法を調べる。

c++でphp extensionを作成する。


また、次元圧縮は、引数で、その割合を指定できるようにする。

てかそもそも、全部 PHP Extensionに押し込めるか。
共起行列の作成とかも、全部、PHP Extensionに押し込めないかな。。
ただ、データの受け渡しがチョイ不安なので、
今は、行列計算の部分だけにしとく。



3、特徴ベクトルの作成
共起行列Aを特異値分解すると、以下の3つに分解される。

A = U * S * V.transpose

U : 左特異行列 (文書の特徴を表す)
S : 特異値行列
V : 右特異行列 (語句の特徴を表す)
※ transposeは転置行列

括弧内は、行を文書、列を語句としたときの、
行列が表す意味。
この分解の特徴として、
特異行列の次元を小さくして、Aを復元すると、
Aを近似した行列を求められる点。


① 文書同士を比較したい場合は、
Uの1行を文書の特徴ベクトルとして、コサインをとれば、
1~-1の範囲で、文書の特徴を評価できる。

② 語句であれば、Vのベクトル。

③ 文書と語句の関連性は、復元したAの近似行列の
各要素の大きさで評価できる。

④ 特異分解するときAに含まれていない文書を評価したいときは、
V, Sを使って、Uの特徴ベクトルを作成することができる。

U_Vector = T_Vector.transpose() * V * S.inverse
※ transposeは逆行列

このU_Vectorと、Uの特徴ベクトルでコサインを計算すれば、
①と同様に評価できる。



4、コサインの計算
計算する。


5、感想
ここまで作って見たが、
ニュース同士の関連を数値化することはできたが、
その精度には疑問が残る。

・ もっと対象とする文書、語句を大きくして、潜在意味空間を広げるか。
・ 文書、語句の範囲を絞り、潜在意味空間の質を上げるか。

もうちょっと検討の必要あり。

2011年11月7日月曜日

c++でphp extensionを作成する。

なにはともあれ、

C++でPHP extensionを作成する。


1、スケルトンを作成
# ./ext_skel --extname=eigen
# cd eigen


2、config.m4を修正

① PHP_ARG_WITHのコメントアウトを外す。

② コンパイラの環境変数を設定

CC=/usr/bin/gcc
CXX=/usr/bin/g++


追記 : のちに、以下もつける必要があるとわかった。

CFLAGS="-g -O2 -lstdc++"
CXXFLAGS=-fPIC


③ 拡張子を「c」から「cc」 or 「cpp」にする。
PHP_NEW_EXTENSION(eigen, eigen.cc, $ext_shared)



3、ソースファイルを修正

① 名前の拡張子を修正
# mv eigen.c eigen.cc
② 中身の #includeを extern "C"で囲む

extern "C"{
    #include "php.h"
    #include "php_ini.h"
    #include "ext/standard/info.h"
    #include "php_eigen.h"
}


4、phpizeでconfigure作成
# phpize

5、configure実行
# ./configure

6、makeを実行
# make

※1 ここで「.libs/eigen.o: could not read symbols: Bad value」というエラーが発生した。

(1)config.m4の「CCをg++」にてみた。


CC=/usr/bin/gcc
CXX=/usr/bin/g++
CC=/usr/bin/g++


ダメ。

(2) php_eigen.hも extern "C"を付けた。

ダメ。

(3) ちゃんとエラーを読んでみた。
「/usr/bin/ld: .libs/eigen.o: relocation R_X86_64_32 against `eigen_module_entry' can not be used when making a shared object; recompile with -fPIC」

なるほど。-fPICオプションをつけてコンパイルし直せと。
Makefile or config.m4に追記。
CXXFLAGS=-fPIC

よしできた。

7、make installを実行
# make install

開発するときはいちいちめんどいので、
シンボリックリンクのほうがいいかも。

# sudo ln -s /usr/local/share/php-5.3.8/ext/eigen/modules/eigen.so /usr/lib64/20090626/



8、php.iniの修正
extension=eigen.so

9、実行を確認。

helloworld
?>
できない!?。

※1 「PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib64/20090626/eigen.so' - /usr/lib64/20090626/eigen.so: undefined symbol: __gxx_personality_v0 in Unknown on line 0」
と出る。
ちょっと調べてみると、gccでコンパイルすると出るエラーだと。
確かにsoをコンパイルするとき、gcc使ってたな。

(1) Makefile の CC=gcc を CC=g++にしてみた。
なんか変なエラー出た。

(2) Makefile の CCFLAGS に -lstdc++をつけてみた。
-lstdc++はc++をコンパイルするよってオプション。
g++ は gcc -lstdc++みたいなもんか。

よしできた。



続いて、eigen.cc の中で、eigen3を実行してみる。

9、前作ったサンプルをそのままコピペしてみる。
→ 動いた。

2011年11月5日土曜日

eigen3でsvd

1、cmakeのインストール
クロスプラットフォームのconfigureだと。。
$ sudo yum install cmake

cmakeの使い方


2、eigen3のインストール
$ wget http://bitbucket.org/eigen/eigen/get/3.0.3.tar.gz
$ tar -xvzf 3.0.3.tar.gz
$ cd eigen-eigen
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" ../
$ make
$ sudo make install

※1 makeした後、make checkしたら
すごく時間かかったから途中でやめた。


3、c++のソースを書いてコンパイルしてみた。
eigen3 - getting started
C++の行列計算ライブラリ

$ cat sample.cc

#include
#include
#include
using Eigen::MatrixXd;

int main(int argc, char const* argv[])
{

    MatrixXd X(2,2);
    X(0,0)=5;
    X(1,0)=5;
    X(0,1)=5;
    X(1,1)=1;
    X(1,1)=X(1,0) + X(0,1);
    std::cout << X << std::endl;
    //printf("karino : %d\n",X(1,2));
    return 0;
}

$ g++ -I/usr/local/include/eigen3 sample.cc (eigen3のヘッダファイルを読み込む)
$ ./a.out
 5  5
 5 10



4、特異値分解

以下みたいな雰囲気で行けた。


    MatrixXf m = MatrixXf::Random(4,3);
    cout << "---------------------" << endl;
    cout << "A:" << endl << m << endl;
    JacobiSVD svd(m, ComputeThinU | ComputeThinV);

    MatrixXf S = svd.singularValues();
    MatrixXf U = svd.matrixU();
    MatrixXf V = svd.matrixV();
    MatrixXf SD = S.asDiagonal();

    cout << "---------------------" << endl;
    cout << "U:" << endl << U << endl;
    cout << "S:" << endl << S << endl;
    cout << "Diag:" << endl << SD << endl;
    cout << "V:" << endl << V << endl;


    //cout << "A:" << endl << U * S.transpose() * V << endl;
    cout << "---------------------" << endl;
    cout << "A:" << endl << U * SD *V.transpose() << endl;



5、次元圧縮
したみたいな感じで部分行列を取り出せばよい。
どれだけの部分を抽出するかは自分で決めなきゃならない。



    MatrixXf UB  = U.block(0,0,4,2);
    MatrixXf SDB = SD.block(0,0,2,2);
    MatrixXf VB  = V.block(0,0,3,2);

    cout << "---------------------" << endl;
    cout << "UB:" << endl << UB << endl;
    cout << "SDB:" << endl << SDB << endl;
    cout << "VB:" << endl << VB << endl;

    cout << "---------------------" << endl;
    cout << "A:" << endl << UB * SDB *VB.transpose() << endl;




6、ベクトルの内積。
後で調べる。
こことかいいと思う。

redsvdを使ってみる。

行列分解ライブラリredsvd


1、cmakeのインストール
クロスプラットフォームのconfigureだと。。
$ sudo yum install cmake

cmakeの使い方


2、eigen3のインストール
$ wget http://bitbucket.org/eigen/eigen/get/3.0.3.tar.gz
$ tar -xvzf 3.0.3.tar.gz
$ cd eigen-eigen
$ mkdir build
$ cd build
$ cmake -G "Unix Makefiles" ../
$ make
$ sudo make install

※1 makeした後、make checkしたら
すごく時間かかったから途中でやめた。





3、redsvdのインストール
$ wget http://redsvd.googlecode.com/files/redsvd-0.2.0.tar.bz2
$ tar -xvjf redsvdd-0.2.0.tar.bz2
$ cd redsvd
$ ./waf configure
$ ./waf make
$ sudo ./waf install

※1、「./waf configure」の段階で、「gtest」と「eigen3」がないといわれた。


4、redsvdをコマンドラインから使ってみる。
適当な行列を書いたファイルfile1を準備.

$ redsvd -i file1 -o file1 -r 2

参考にしたサイトに書いてある通り、
3つのファイルが作成された。


5、C++のソースで特異値分解するには?
redsvd-0.2.0/sampleに入っているやつ、
コマンドラインから実行するためのプログラムっぽい。
lsa.cppで定義されている「LSA::processFileList」のなかに、
ぽい部分があったが、うまくいかず・・・。

octaveでもsvdができるらしい。

1、octaveをインストールする。
どうやらEPELレポジ鳥にパッケージあるらしい。

① Centos6にEPEL
$ wget http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-5.noarch.rpm
$ sudo rpm -ivh epel-release-6-5.noarch.rpm

② octaveをインストール
$ sudo yum install octave


実質ここまで。。



2、octaveを使ってみる。
liboctaveの基礎

いまいちまだ使えん。


3、octaveで特異値分解
Octave C++で数値計算

※1 SVDを入れると、
「undefined reference to~」ってエラーが要所要所で出る。


※2 octaveをコマンドラインから実行すると、
「octave: error while loading shared libraries: libhdf5.so.6: cannot open shared object file: No such file or directory」というエラーが出る。


yumprovidesで調べても見たが・・・、よくわからん。
$ yum provides \*/libhdf5.so.6
hdf5は最新が入ってる。



調べてみると、同じ症状の人がいた。
シンボリックリンク張ったらとりあえず動いたが。
いいのかこれ。
$ sudo ln -s /usr/lib64/libhdf5.so.7 /usr/lib64/libhdf5.so.6

2011年11月2日水曜日

テキストマイニングに関する論文を読んだ時のメモ

1、文書クラスタリングによるトピック抽出および課題発見
東工大橋本らが行っている研究。
ここでは、大量の文書をクラスタリングソフト(cluto)で系統樹を作成し、
さらにそれを分類することで、大量の情報をわかりやすい形にしようとしている。。

各文章毎に文章から代表的な単語を抽出して単語ベクトルを作成する。

クラスタリングソフトには、文書毎の単語の出現頻度(共起行列?)をわたし、
潜在的意味解析を行っているものと思われる。
bayonとかの中でもそれを行っているんだろうか。

2、社会課題発見のための文書クラスタリングとクラスタ評価指標
1の研究と同じ。「密度」や「中心度」に関してもう少し詳しく説明されている。


3、単語と意味属性との共起に基づく概念ベクトル生成手法
1で使われる単語ベクトルの概念が結構わかりやすく示されている。


4、新聞記事内容と株価変動の関連性の定量的分析
過去の新聞記事内容と株価の変動をひもづけておいて、
今の新聞記事の中から、株価の変動にかかわりそうな
記事を抽出する研究。
共起語に新聞から抽出した単語をそのまま使うのではなく、
単語間の意味的な依存関係を使っているみたい。


5、 主題語からの話題語自動抽出と、これに基づく Web 情報検索
1つの検索キーワード(主題語)から、一定の法則で話題語を抽出し、
主題語と話題語から検索されるWebページの特徴ベクトルと
主題語のみから検索されるWebページの特徴ベクトルを比較し、
近いものを検索結果とする研究。
これによりどの程度精度がよくなるかはわからないが、
面白い研究。

phpからRを使う

方法として見つけたのは2つ。

1、R-php エクステンションを入れる
2、proc_open()でRを呼び出す。


1、R-php エクステンションを入れる
R-phpをインストール・使ってみた

① mysqlとImagemagickを追加する。
$ sudo yum install php-mysql mysql mysql-server ImageMagick ImageMagick-devel

② Rのインストール
CentOS5.5で、yumでRをインストール


③ R-phpをダウンロード・インストール
# wget --content-disposition 'http://dssm.unipa.it/R-php/?cmd=downPack&pack=R-php-1.tar.gz'
# tar -xvzf R-php-1.tar.gz

④ 解凍したディレクトリをapacheのドキュメントルートに移動。。

・・・

これは、phpmyadminみたいなソフトと考えたほうがいい。
やる前にちゃんと読め。。

Rを実行している部分を探した。
(1)R-php/R/pages/home/index.phpで、テキストエリア(codice)にRコードを打たせる。
(2)R-php/R/pages/result/index.phpで、postされたcodiceを受け取り、ファイルに格納。
(3)R-php/R/pages/result/index.phpで、execコマンドをつかい、Rを実行する。

exec("$R_command -q --no-save < codice.txt > result 2>&1");



2、proc_openでRを呼び出す。
R言語とPHPの連携

proc_openでRを実行して、
fwrite、freadでRとやり取りしているみたい。

2011年11月1日火曜日

centos6でrpmforge

RPMforgeをインストール


$ wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm
$ sudo rpm -i rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm

必要に応じて、
$ sudo vim /etc/yum.repo.d/rpmforge.~ 
を修正。

2011年10月31日月曜日

データクラスタリングツールbayon

bayonとclutoって2つを見つけた。
どうやら、clutoは商用利用に制限がある模様。


とりあえず、bayon。

bayonのチュートリアル

bayonを使った記録


1、インストール
# wget http://bayon.googlecode.com/files/bayon-0.1.0.tar.gz
# tar -xvzf bayon-0.1.0.tar.gz
# cd bayon-0.1.0
# ./configure
# make
# make install


2、インプットの準備
$ cat data.tsv
ドキュメントID1 (タブ) フレーズ (タブ) 値  (タブ) フレーズ (タブ) 値 ・・・
ドキュメントID2 (タブ) フレーズ (タブ) 値  (タブ) フレーズ (タブ) 値 ・・・
ドキュメントID3 (タブ) フレーズ (タブ) 値  (タブ) フレーズ (タブ) 値 ・・・
ドキュメントID4 (タブ) フレーズ (タブ) 値  (タブ) フレーズ (タブ) 値 ・・・
ドキュメントID5 (タブ) フレーズ (タブ) 値  (タブ) フレーズ (タブ) 値 ・・・


3、実行
$ bayon -n 3 -p data.tsv

3クラスタに分類する。

※ PHPから利用する事はできないですかね?。

Repeated bisection 法とk平均法

bayonで使えるデータクラスタリング手法
1、Repeated bisection 法
2、k平均法




1、Repeated bisection 法
誰かの論文

抽出した特徴語を用いて情報を分類する.Repeated bisection はクラスタリングツールCLUTO で使用されているクラスタリング手法であり,情報を 2 分割していくことでクラスタリングを実行する.このクラスタリング手法はソートアルゴリズムの中でも高速かつ軽量なクイックソートアルゴリズムに類似している部分があり,大量の情報を高速に扱うことができる.Repeated bisection の概要を図 4.7 に示す.まず,情報集合の中からランダムに 2つ要素を選択し,それぞれを格納する情報集合を作成する.元の情報集合の全ての要素に対して,ランダムに選択した 2 つの要素との類似度を比較し,高い情報集合に格納する.さらに情報集合の中で類似度をそれぞれ比較し直し,情報の移動を行う.これらの一連の動作を
規定数繰り返すことによって,情報を分類する.




2、k平均法
k平均法
  1. 各点にランダムにクラスタを割り当てる
  2. クラスタの重心を計算する。
  3. 点のクラスタを、一番近い重心のクラスタに変更する
  4. 変化がなければ終了。変化がある限りは 2. に戻る。

新着質問を取得する。

はてなや、yahoo知恵袋から、質問をかき集めてくる。
必要な情報としては、

「タイトル」、「質問内容」、「回答に必要な情報」



① はてな取得先API(はてなウェブサービス
はてな : http://q.hatena.ne.jp/list/computer?mode=rss
URIに接続すれば、xml形式で返却してくれる。


② yahoo知恵袋(yahoo ディベロッパーネットワーク
yahoo知恵袋 : http://chiebukuro.yahooapis.jp/Chiebukuro/V1/getNewQuestionList
yahooのIDを作成しなければならない。
その後、アプリケーションIDを作成する。


③ facebook



※ PHPで取得する。
$r = new HttpRequest('http://q.hatena.ne.jp/list/computer?mode=rss',HttpRequest::METH_GET);

 
try{
   $r->send();
   if ($r->getResponseCode()==200) {
      $str = $r->getResponseBody();
      echo $str;
   }else {
      echo "error";
   }
}catch(HttpException $ex){
   echo $ex;
}



【メモ】
1、はてなウェブサービス( Hatena Developer Center )
2、yahoo ディベロッパーネットワーク
3、facebook
4、mixi
5、okwave
6、アメーバ

2011年10月29日土曜日

php でパケットキャプチャを行う2

今更ながら、pcaplibを使った方が、
うまくいくパケットキャプチャできるのでは?


libpcap - 私的メモ

libpcapリファレンス

tcpdumpにおけるlibpcapの使われ方


※1、コンパイルオプションに、「-lpcap」を加える必要がある。


典型的なlibpcap利用の流れ。
(細かい引数とかは、リファレンスを参考にする)

1,deviceをプロミスキャスモードでオープンする。


   // get device
   if (argc != 2) {
      dev = pcap_lookupdev(errbuf);
      if (dev == NULL) {
              fprintf(stderr, "no device\n",errbuf);
              exit(1);
      }
   }else if(argc == 2){
      dev = argv[1];
   }
   printf("dev: %s\n",dev);

   // open device
   handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
   if (handle == NULL) {
           fprintf(stderr, "cannot open device\n",errbuf);
           exit(1);
   }else {
           printf("open device : %s\n",dev);
   }


2,フィルタをコンパイルしてセットする。


   // compile filter
   if(pcap_compile(handle, &fp, filter_exp, 0, net)==-1){
           fprintf(stderr, "cannot compile filter\n",errbuf);
           exit(1);
   }else{
           printf("compile filer success\n");
   }

   // setting filter
   if (pcap_setfilter(handle, &fp) == -1) {
           fprintf(stderr, "cannot set filter\n",errbuf);
           exit(1);
   }


※ filter_expにセットする文字列は、tcpdumpのオプションと一致する。たぶん。

3,パケットを取得する。
方法1 : pcap_next
パケットを1個取得して、返却する。


   packet = pcap_next(handle, &header);
   if(packet == NULL){    
      return;
   }
   // read packet
   pkt = packet_read(NULL,handle,packet);

※ packet_readは、方法2のコールバック関数をちょっと修正したもの。
基本やることは同じ。



方法2 : pcap_loop
パケットを受け取ったらコールバック関数を実行する。

   cnt = 1;
   //if (pcap_loop(handle, cnt, printer, NULL) < 0) {
   if (pcap_loop(handle, cnt, got_packet, NULL) < 0) {
           fprintf(stderr, "pcap_loop error: %s\n",pcap_geterr(handle));
           exit(1);
   }



【現在の問題点メモ】

1,srcipとdstipが同じになってしまう。
inet_ntoaの落とし穴で対応する。

2,HTTPヘッダ情報からうまく欲しい情報を抽出できていない。
PHP側で対処可能だとおもう。

3,長時間実行すると(多くのパケットを取ると)落ちる。
たぶんメモリを開放してないとかそういうのだと思う。

4,パケットの量が多いと取りこぼす。
コールバックの形をトラずPHPに送っているから仕方ないのか。
PHPから使うとき、filterの設定をしっかりして、
対象範囲を限定すればなんとかなるか。






php extensionを作成する ~クラスの書き方~

この記事を読むと・・・、

$obj = new Mypcap();
echo $obj->interface();
echo $obj->filter();


$pkt = $obj->get_packet();

echo $pkt->srcip
echo $pkt->dstip
echo $pkt->protocol
echo $pkt->sport
echo $pkt->dport
echo $pkt->http_request


見たいなコードを書けるようになる。


PHP拡張でクラス実装がよくわからん

DSAS開発者の部屋 PHPextension 第3回

※ helloworldくらいは作っておく。


1,クラスの作成

① php_mypcap.h に追記
static zend_class_entry *mypcap_ce;

② mypcap.c の PHP_MINIT_FUNCTION(mypcap) に追記
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Mypcap", mypcap_functions);
mypcap_ce = zend_register_internal_class(&ce TSRMLS_CC);

zend_declare_property_string(mypcap_ce, "interface", strlen("interface"), "eth2", ZEND_ACC_PUBLIC)

zend_declare_property_string(mypcap_ce, "filter", strlen("filter"), "tcp", ZEND_ACC_PUBLIC)


return SUCCESS;

これでクラスのインスタンスを生成できるようになる。
このクラスには、interfaceとfilterというプロパティ(メンバ変数)がある。


2,メソッドの作成

① php_mypcap.h にメッソド名を宣言
PHP_METHOD(mypcap, get_packet);

② mypcap.c の mypcap_functions にメッソド名を追記する。
PHP_ME(mypcap, get_packet, NULL, 0);


③ mypcap.c の最後の方に関数を実装する。
PHP_METHOD(mypcap , get_packet){
  printf("get");
  return
}

※1 メソッド内で、メンバ変数を読み込む方法。
zval *interf;
obj = getThis();
interf = zend_read_property(Z_OBJCE_P(obj),obj, "interface",strlen("interface"), 1 TSRMLS_CC);
printf("%s\n", interf->value.str.val);


※2 メソッド内で、引数を取得する方法。
char *arg;
int arg_len;
if(zend_parse_parameters(ZEND_NUMARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE)
{return;}
printf("%s\n",arg);


※3 メソッドで、インスタンスを返り値とする方法。
zval *pkt;

// オブジェクト生成
MAKE_STD_ZVAL(pkt);
if(object_init(pkt) != SUCCESS){}
add_property_stringl(pkt, "srcip","",strlen(""),1);
add_property_stringl(pkt, "dstip","",strlen(""),1);
add_property_stringl(pkt, "protocol","",strlen(""),1);
add_property_longl(pkt, "sport",0);
add_property_longl(pkt, "dport",0);
add_property_stringl(pkt, "http_requ","",strlen(""),1);

// オブジェクト返却
*return_value = *pkt;
zval_copy_ctor(return_value);

return;

PHP: Zend API: PHPのコアをハックする。
ここを参考にした。

PHPエクステンションから戻り値を~
ここも参考にした。

2011年10月25日火曜日

cakephp、URL接続後の流れ

http://paymo.j-payment.co.jp/payform/101071に接続した後の
流れを追って見る。


1、URL接続 → ドキュメントルートを参照
apacheに設定されているドキュメントルートを参照する。
この場合、
/home/httpd/www/paymo/payform/101071
を参照する。



2、トップで、mod_rewirteによる参照先を書き換え
cakephpのトップには、「.htaccess」が置かれている。
この中には、mod_rewriteの設定が書かれている。
RewriteEngine on
RewriteRule    ^$    app/webroot/      [L]
RewriteRule    (.*) app/webroot/$1    [L]

これは、RewriteRule (正規表現) (文字列)
(正規表現)に一致した部分を、(文字列)に書き換えるということ

^$ : 先頭から末尾まで何もない。
(.*) : 何でもいい一文字(.)の繰り返し(*)。

つまり、
引数なしの場合 → app/webroot/
引数ありの場合 → app/webroot/引数

今回の場合、

/home/httpd/www/paymo/payform/101071

/home/httpd/www/paymo/app/webroot/payform/101071

を参照することになる。




3,webrootで、mod_rewirteによる参照先を書き換え

webrootに飛ばされたあと、更にrewriteされる。

RewriteEngine On
RewriteCond %{REQUEST_FILENAME}  !-d
RewriteCond %{REQUEST_FILENAME}  !-f
RewriteRule ^(.*)$ index.php?url=$1 [QSA,L] 

RewriteCondは、RewriteRuleを適用する条件を設定する。
RewriteCondについて
 
RewriteCond (対象) (条件)
REQUEST_FILENAME : 接続先のファイル名
!-d : 存在するディレクトリ名にはルールを適用しない。
!-f : 存在するファイル名にはルールを適用しない。

※ 「存在する」を確認する範囲は?

この条件に一致する場合、RewriteRuleを適用する。
この場合、
/home/httpd/www/paymo/app/webroot/payform/101071

./index.php?url=/home/httpd/www/paymo/app/webroot/payform/101071

となり、app/webroot/index.phpがよびだされる。



4,app/webroot/index.phpの中では。
いろんな定数の定義が行われる。主にパス。
ROOT, APP_DIR, CAKE_CORE_INCLUDE_PATH, WEBROOT_DIR等を、
app/webroot/index.phpからさかのぼって設定している。

パスの設定が終わったら、
CORE_PATH/cake/bootstrap.php
(/home/httpd/www/paymo/cake/bootstrap.php)をincludeする。

bootstrap.phpの中では、更に
「/cake/basics.php」、
「/cake/config/paths.php」、
「/cake/libs/のなかみ幾つか」が読み込まれている。
また、「Configure::getInstance()」で、Appインスタンスを生成している。

$_GET['url ']が入っていることを確認して、
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch();
を呼び出す。


5、Dispatcherでやること。
 Dispatcherは、「cake/dispatcher.php」で定義されており、
bootstrap.phpの中で、読み込まれている。

function dispatchのコメントを読む限り、
この関数で、URLを読み、該当するコントローラを参照し、
表示までしているとのこと。

「paramsの設定」や「dataの設定」もここでやっている模様。


とりあえずここまで。
もうちょっと追わないと、
formからdataを受け取れる仕組みはわからないかも。。






正規表現

便利なサイト

php でパケットキャプチャを行う

方法としては以下の2通り

① phpのソケットapiを利用する。
作業量は少なくなりそうだが、
パケットキャプチャに関する参考資料が少ない。

phpのソケットapiリファレンス
phpのソケットapiでサーバを作る

また、パケットキャプチャに必要な、
ソケットのドメインAF_PACKET(PF_PACKET)が
使えないかもしれない。。


② Cで書いて、phpエクステンションにする。
パケットキャプチャの資料は多そうだが、
phpエクステンションのハローワールドから
はじめる必要がある。


Cでパケットキャプチャ1
Cでパケットキャプチャ2
phpエクステンションの作り方


②の方法で行く事にする。

1、スケルトン作成
# cd /usr/local/share/php-5.3.8/ext/
# ./ext_skel --extname=pcap
# cd pcap

config.m4を修正
dnl PHP_ARG_ENABLE(エクステンション名, whether to enable エクステンション名 support,
dnl Make sure that the comment is aligned:
dnl [ --enable-エクステンション名 Enable エクステンション名 support])
この3行のdnlを消して保存する。

KLabのブログに書いてあった場所とは異なる。
ここの意味は何なのか?


2、コンパイル
# phpize
# ./configure
# make

3、ソース修正
php_pcap.h
pcap.c
をそれぞれ修正して、再度コンパイル


4、シンボリックリンク作成
# cd /usr/lib64/20090626/
# sudo ln -s /usr/local/share/php-5.3.8/ext/pcap/modules/pcap.so ./pcap.so

php.iniにパスを通す。


5、ソースを書く。
[1] PHP extensionとして作っているところ
[2] こCのパケットキャプチャを作っているところ
書いてみて共通しているところ、ちがうを探してみた。

① socketのタイプ
[1]では、ドメイン:AF_PACKET、タイプ:SOCK_RAWを使っていたが、
[2]では、ドメイン:PF_PACKET、タイプ:SOCK_DGRAMを使っていた。


う~ん。
pcap使ったほうがいいのかも