差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン前のリビジョン次のリビジョン | 前のリビジョン | ||
dokuwiki:localize [2006/03/27 12:05] – osamu | dokuwiki:localize [2007/07/31 15:36] (現在) – osamu | ||
---|---|---|---|
行 1: | 行 1: | ||
+ | ====== DokuWikiの日本語対応 ====== | ||
+ | [[doku> | ||
+ | <code php> | ||
+ | $conf[' | ||
+ | </ | ||
+ | と記述されて、ユーザーインターフェースの文字列などは日本語になる。 | ||
+ | 機能面での日本語対応を強化するために、次の改造を加える。 | ||
+ | ===== メールのエンコード ===== | ||
+ | DokuWikiでは、文書を誰かが編集したときなどにお知らせのメールを送る機能があるが、そのメールのエンコードを自前のUTF-8化ルーチンで行っている。日本語のメールはUTF-8ではなくISO-2022-JPでエンコードするのが通例なので、内蔵のmb_send_mail関数が使える場合はそちらを使って$conf[' | ||
+ | |||
+ | inc/ | ||
+ | <code php> | ||
+ | function mail_send($to, | ||
+ | if(defined(' | ||
+ | $subject = utf8_deaccent($subject); | ||
+ | $subject = utf8_strip($subject); | ||
+ | } | ||
+ | </ | ||
+ | の直後に | ||
+ | <code php> | ||
+ | global $conf; | ||
+ | if (function_exists(' | ||
+ | $header | ||
+ | $header .= $headers; | ||
+ | $header | ||
+ | mb_language($conf[' | ||
+ | if($params == null){ | ||
+ | return @mb_send_mail($to, | ||
+ | }else{ | ||
+ | return @mb_send_mail($to, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | を追加。 | ||
+ | |||
+ | |||
+ | ===== 検索の日本語対応 ===== | ||
+ | DokuWikiでは自前の全文検索エンジンを搭載している。 | ||
+ | |||
+ | 新しいページを登録するときに、全文検索のインデックス(なんという単語がどのファイルにいくつ入っているかを記録した索引)ファイルの中に、登録したページの索引情報を記録するようになっているのだが、ページの中から単語を切り出すのに空白文字で区切られたところを単語と認識して処理している。 | ||
+ | |||
+ | 日本語のように、単語の間に空白文字を書かない文書をこのプログラムに通すと、日本語の文字が全部ひとつながりになって1単語と認識されて登録されてしまう。たとえば、“DokuWikiでは自前の全文検索エンジンを搭載している。”という文は“DokuWiki”と“では自前の全文検索エンジンを搭載している。”という2つの単語として索引に登録されてしまう。このため、例えば“全文検索”とか“エンジン”とかで検索してもこのページはヒットせず、“では自前の全文検索エンジンを搭載している。”で検索して初めてヒットする、ということになってしまう。 | ||
+ | |||
+ | これを解決するために、索引に登録するところで日本語の文章の単語の間に空白を入れる処理を追加する。日本語の文章を分かち書きに変換するプログラムとしてはkakasiが有名だが、kakasiは標準ではUTF-8のテキストに対応していない。 | ||
+ | '' | ||
+ | などと、前後に文字コード変換プログラムのnkfやiconvを使って無理やりUTF-8→EUC-JP→UTF-8 という変換をするという手もあるが、効率が悪いし、なによりかっこ悪い。そこで、UTF-8に対応していて、kakasiより数倍早いという触れ込みのMeCabを使ってみる。 | ||
+ | |||
+ | ==== MeCabのインストール ==== | ||
+ | [[http:// | ||
+ | 別にダウンロードする辞書ファイルは「ipadic-2.4.4/ | ||
+ | |||
+ | UTF-8の環境で使えるようにconfigureする。 | ||
+ | |||
+ | < | ||
+ | |||
+ | / | ||
+ | '' | ||
+ | '' | ||
+ | |||
+ | configureしたら、あとはmakeするだけ。 | ||
+ | |||
+ | < | ||
+ | $ make install</ | ||
+ | |||
+ | インストールしたら、正しく分かち書きできるかどうか試してみる。 | ||
+ | |||
+ | < | ||
+ | 上野発の夜行列車降りたときから青森駅は雪の中 | ||
+ | 上野 発 の 夜行 列車 降り た とき から 青森 駅 は 雪 の 中 | ||
+ | ^D</ | ||
+ | のように、入力した文字が分かち書きされて表示されればOK。 | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ==== 全文検索インデクサーの改造 ==== | ||
+ | MeCabで分かち書きをさせるには、'' | ||
+ | PHP 4.3で追加されたproc_open()関数を使って、パイプ渡しでテキストを分かち書き処理させる。 | ||
+ | |||
+ | inc/ | ||
+ | |||
+ | どこか先頭に近いところに | ||
+ | <code php> | ||
+ | define (' | ||
+ | </ | ||
+ | を追加。これで、分かち書きをする外部プログラムの名前(シェルで呼び出すときのコマンド)を定数定義。kakasiを使うなら'' | ||
+ | 本当は'' | ||
+ | |||
+ | あとは、検索対象の文字列をtoken(単語)に切り分ける部分の直前で、この外部プログラムを呼び出すようにするだけ。 | ||
+ | function idx_getPageWords($page)の | ||
+ | <code php> | ||
+ | list($page, | ||
+ | </ | ||
+ | と | ||
+ | <code php> | ||
+ | $body = strtr($body, | ||
+ | </ | ||
+ | の間に | ||
+ | <code php> | ||
+ | | ||
+ | | ||
+ | 0 => array(" | ||
+ | 1 => array(" | ||
+ | 2 => array(" | ||
+ | ); | ||
+ | $process = proc_open(PRE_TOKENIZER, | ||
+ | if(is_resource($process)) { | ||
+ | stream_set_blocking($pipes[0], | ||
+ | stream_set_blocking($pipes[1], | ||
+ | fwrite($pipes[0], | ||
+ | fclose($pipes[0]); | ||
+ | |||
+ | $body = ''; | ||
+ | while(!feof($pipes[1])) { | ||
+ | $body .= fgets($pipes[1], | ||
+ | } | ||
+ | fclose($pipes[1]); | ||
+ | proc_close($process); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | を追加 | ||
+ | |||
+ | function idx_tokenizer($string,& | ||
+ | <code php> | ||
+ | $words = array(); | ||
+ | </ | ||
+ | の後ろに | ||
+ | <code php> | ||
+ | if(function_exists(proc_open) && defined(' | ||
+ | $dspec = array( | ||
+ | 0 => array(" | ||
+ | 1 => array(" | ||
+ | 2 => array(" | ||
+ | ); | ||
+ | $process = proc_open(PRE_TOKENIZER, | ||
+ | if(is_resource($process)) { | ||
+ | stream_set_blocking($pipes[0], | ||
+ | stream_set_blocking($pipes[1], | ||
+ | fwrite($pipes[0], | ||
+ | fclose($pipes[0]); | ||
+ | $string = ''; | ||
+ | while(!feof($pipes[1])) { | ||
+ | $string .= fgets($pipes[1], | ||
+ | } | ||
+ | fclose($pipes[1]); | ||
+ | proc_close($process); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | を追加。 | ||
+ | |||
+ | DokuWikiの最近のバージョンでは、日本語を含むアジア圏の文字を1文字1単語とみなして検索する修正が入っているが、これを使うと例えば「文字を探す」で検索すると「文」「字」「を」「探」「す」のすべての文字が検索結果でハイライトされたりして具合がよくない。上記の修正を加えたときは、idx_tokenizer($string,& | ||
+ | <code php> | ||
+ | $asia = @preg_replace('/ | ||
+ | if(!is_null($asia)) $word = $asia; //recover from regexp failure | ||
+ | </ | ||
+ | という2行をコメントアウトする。 | ||
+ | また、indexer.phpにwordlen()という関数があるが、これも同じくアジア圏の文字は1文字1単語とみなす処理が入っているので | ||
+ | <code php> | ||
+ | function wordlen($w){ | ||
+ | // $l = strlen($w); | ||
+ | |||
+ | $l = utf8_strlen($w); | ||
+ | |||
+ | //// If left alone, all chinese " | ||
+ | //// So the " | ||
+ | // | ||
+ | // $l += ord($w) - 0xE1; // Lead bytes from 0xE2-0xEF | ||
+ | |||
+ | return $l; | ||
+ | } | ||
+ | </ | ||
+ | と変更。 | ||
+ | |||
+ | それから、同じくindexer.php の idx_getIndexWordsSorted() 関数の中に、 | ||
+ | <code php> | ||
+ | if ($wlen < 3 && $wild == 0 && !is_numeric($xword)) continue; | ||
+ | </ | ||
+ | という部分があるが、このままだと3文字より短い単語を検索できない。英語などではそれでもよいのだが、日本語の場合1~2文字の単語も検索できないと困るので、これを | ||
+ | <code php> | ||
+ | if (preg_match('/ | ||
+ | </ | ||
+ | と書き換える。 | ||
+ | |||
+ | |||
+ | //2005-12-8 - Mecabのプロセスがハングアップして残ってしまうのを避けるために'' | ||
+ | //2007-7-29 - DokuWikiの最近のバージョンにあわせて、修正箇所の説明を変更// | ||
+ | |||
+ | |||
+ | ==== 全文検索インデクサーの不具合修正 ==== | ||
+ | 以上で全文検索の日本語対応改造は完了だが、本日現在の最新バージョン(20050922)には、全文検索機能にもとからバグがあるようで、ASCII文字以外の文字が混ざった単語を検索すると、検索結果ページで表示されるヒット数が全部1になってしまう。 | ||
+ | これに対する修正を加える。 | ||
+ | 上と同じ'' | ||
+ | <code php> | ||
+ | $words[$w] = $c + (isset($words[$w]) ? $words[$w] : 0); | ||
+ | </ | ||
+ | という行を | ||
+ | <code php> | ||
+ | $words[$w] = $c * $count + (isset($words[$w]) ? $words[$w] : 0); | ||
+ | </ | ||
+ | に変更(‘'' | ||
+ | |||
+ | この変更後、修正したり新規に追加したりして保存しなおしたファイルは、検索結果のヒット数が正常に表示されるようになる。 | ||
+ | http:// | ||
+ | |||
+ | // 追記: この不具合は、現在配布されているバージョンでは修正されています。// |