mecabに新しい辞書を追加する

mecabに新しい辞書を追加した際の手順の記録。

1.辞書の元になるデータをダウンロードする

データとしてよく利用されているものに、wikipediaのタイトルリストやはてなキーワード、人名事典などがある。今回はwikipediaのタイトルリストを利用した。(はてなキーワードも追加した。このページの下のほう)

ダウンロード先URL
-------------------------------------

http://dumps.wikimedia.org/jawiki/latest/jawiki-latest-all-titles-in-ns0.gz

-------------------------------------

人名事典ならこちらのページからダウンロードできる
(個人的には人名事典は使わない。人名が普通名詞と結構かぶって、名詞の読みが人名なったり、長めの普通名詞が人名と区切られたりと不都合が起こる)
-------------------------------------

http://www.mwsoft.jp/programming/munou/ime_dictionary_link.html#person

-------------------------------------

2.不要なタイトルは削除する

ここからタイトルリストをCSVファイルに加工していく。保存名はwikipedia.csvとした。
まず秀丸エディタで開き、置換の繰り返しで不要タイトルを削除した。

個人的に削除したタイトルの条件

・数字だけのもの
・「(曖昧さ回避)」を含むもの
・3文字以下のもの

・次の言葉で始まるタイトル
-------------------------------------
「日本の~」「日本に~」「日本と~」「日本で~」
「中国に~」「中国の~」
「アメリカに~」「アメリカの~」
「ヨーロッパに~」「ヨーロッパの~」
「.(ドット)~」
-------------------------------------

次の文字を含むタイトル
-------------------------------------
「,(カンマ)」←あるとフォーマットエラーになる。カンマを残すならエスケープが必要。
-------------------------------------

・次の言葉で終わるタイトル
-------------------------------------
「_(何か)」「一覧」「の登場人物」
-------------------------------------

秀丸エディタのマクロで置換するファイル: 右クリックしてダウンロード

3.辞典に登録できる状態に整形する

辞書に登録されている単語は通常CSVファイルでこのようになっている

-------------------------------------
工藤,1223,1223,6058,名詞,固有名詞,人名,名,*,*,くどう,クドウ,クドウ
-------------------------------------

値の意味は左から
-------------------------------------
表層形,左文脈ID,右文脈ID,コスト,品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用形,活用型,原形,読み,発音
-------------------------------------

なので一旦こうした。(スコア)は後で数字に置き換える。

-------------------------------------
日清どん兵衛
-------------------------------------

↓↓↓

-------------------------------------
日清どん兵衛,0,0,(スコア),名詞,固有名詞,*,*,*,*,日清どん兵衛,*,*,ウィキペディア
-------------------------------------


<20150814 追記>
固有名詞のスコアは1でいいと思う。
-------------------------------------
日清どん兵衛,0,0,1,名詞,固有名詞,*,*,*,*,日清どん兵衛,*,*,ウィキペディア
-------------------------------------

このとき利用した秀丸エディタの正規表現

検索:^(.+)$

置換:¥1,0,0,(スコア),名詞,固有名詞,*,*,*,*,\1,*,*,ウィキペディア


<20150814 追記>
スコア1の場合
-------------------------------------

置換:¥1,0,0,1,名詞,固有名詞,*,*,*,*,\1,*,*,ウィキペディア
-------------------------------------

次にスコアを登録する。
コストは、その単語がどれだけ出現しやすいかを示していて、小さいほど出現しやすいという意味になるらしい。

長いキーワードが優先されるよう設定したいので、文字数に比例してコストが小さくなるように設定した。こちらのサイトにある式を参考にコスト値を求める。

コストを求める式
-----------------------------------------
コスト値 = -400 * (文字の長さの1.5乗)の整数
但し、最小で-36000
-----------------------------------------

スコアの登録はUWSCでファイルから一行ずつ読み込んで置換。(秀丸エディタでの計算がよくわからなかったので)

//UWSCファイルの一部抜粋
///////////////////////////////////////////////////////

//タイトルの文字数
moji_suu = POS(",0,0,(スコア)",Line_data) - 1

cost = 0 //初期化

//文字数がマイナス(取得失敗)でべき乗するとエラーが出るようなのでIFで回避
IFB moji_suu > 0
cost = INT(-400 * POWER(moji_suu, 1.5))
 IF cost < -36000 THEN cost = -36000 ENDIF Line_data = REPLACE(Line_data,"(スコア)", cost) /////////////////////////////////////////////////////// 最初からすべてUWSCでやればよかったとも思った。秀丸エディタで面倒な置換を何度も繰り返す必要なかったなと。 4.辞書のコンパイルとインストール

これ以降の作業は必要な辞書を全部そろえてからでいい。

参考サイト

辞書登録には「システム辞書」と「ユーザー辞書」があるが今回はシステム辞書に追加する。(登録に時間はかかるが解析は早い)

csvファイルをmecab-ipadic-2.7.0-20070801ディレクトリに移動する。
ここにcsvファイルも入れておく。この際、改行コードも「LF」になってることを確認した。

自分の環境のパス(cd でココに移動
--------------------------------------------
/home/username/local/mecab-ipadic-2.7.0-20070801
--------------------------------------------
※↑おそらくこのパスは、辞典CSVファイルが入ったディレクトリならどこでもいい。既に消去してしまっていたら、一時ファイルを作ればいいと思う。そこで次のコマンドを実行する。

mecab-dict-indexを実行するので場所を確認
--------------------------------------------
/home/username/local/libexec/mecab/mecab-dict-index
--------------------------------------------
mecabが使える状態ならどこかにあるはず

コマンドを実行する。

実際のコマンド
--------------------------------------------
/home/username/local/libexec/mecab/mecab-dict-index -f utf8 -t utf8
--------------------------------------------
「-f」はCSVの文字コード、-「t」はバイナリ辞書の文字コードを指定。
「mecab-ipadic-2.7.0-20070801」がカレントディレクトリでないとエラーが出る

また、最初に実行した際、こんなエラーも出た
--------------------------------------------
reading ./wikipedia.csv ... dictionary.cpp(167) [n == 5] format error:
--------------------------------------------

「,」を含むタイトルが残っていて、削除することでうまくいった。

最後にインストールも忘れずに行う
--------------------------------------------
make install
--------------------------------------------
※もし、インストール前のmecabディレクトリを消してしまっていた場合、インストールはできない。そのときはインストールは諦めて、新しくできた辞書ファイルを所定の場所に移動させる(置換)で辞書を追加することができる。

移動させるファイル名
------------------------------------------
char.bin
sys.dic
unk.dic
matrix.bin
------------------------------------------

移動前(ファイルができる場所)
------------------------------------------
/home/username/local/mecab-ipadic-2.7.0-20070801
------------------------------------------
↓↓↓

移動先
------------------------------------------
/home/username/local/lib/mecab/dic/ipadic
------------------------------------------

はてなキーワードの登録もやってみた

やりかたはwikipediaのときとほぼ一緒。

1.データをダウンロード

ダウンロード元
----------------------------
•http://d.hatena.ne.jp/images/keyword/keywordlist_furigana.csv
----------------------------

2.CSVファイルの整形

次の条件のタイトルは削除。

・「,(カンマ)」を含むもの
・「2001-01-01」のような日付だけのもの
・数値文字参照「&#~」を含むもの
・「ぱーせんとぜろぜろ」のタイトル(UTF-8に文字コード変換するとタイトルの%00(?
)が半角スペースに置き換わり、インストールエラーが出る。こんなの→「empty word is found, discard this line」)
・「明日(ぬくい)」という人名。残しておくと、「明日(あした)」が「ぬくい」と解釈されて邪魔
・「???」という項目

秀丸エディタのマクロで置換するファイル: 右クリックしてダウンロード

そして、辞書用に並び替え。
-----------------------------------------------------------------
ひかりのもり(タブ)光の森
-----------------------------------------------------------------

↓↓↓

-----------------------------------------------------------------
光の森,0,0,(スコア),名詞,固有名詞,*,*,*,*,光の森,ひかりのもり,ひかりのもり,はてなキーワード
-----------------------------------------------------------------

wikipediaのタイトルリストと違い、多くのタイトルにふりがな情報がある。

実際に使った秀丸エディタの正規表現

ふりがながある項目に対して有効
-----------------------------------------------------------------
検索:^(.+)\t(.+)$

置換:\2,0,0,(スコア),名詞,固有名詞,*,*,*,*,\2,\1,\1,はてなキーワード
-----------------------------------------------------------------

ふりがながない項目用に次の置換も実行
-----------------------------------------------------------------
検索:^\t(.+)$

置換:\1,0,0,(スコア),名詞,固有名詞,*,*,*,*,\1,*,*,はてなキーワード
-----------------------------------------------------------------

上記の正規表現で置換すると、ふり仮名のないタイトルにおいて、空欄「,,(連続カンマ)」ができてしまう。空欄は「*」に置き換える「,,」→「,*,」

あとは(COST)の部分を数値に置き換えて「mecab-dict-index」を実行、そしてインストール「make install」。(もしくは、ファイル移動)

さくら共用サーバーにmecabをインストールする

さくら共用サーバーで php-mecab を使うだけならサービスに元々含まれている mecab を利用できる。自前の mecab は不要なのでこのエントリーの作業は不要。自前で mecab はインストールすべき。デフォルトの mecab は php のバージョンアップなどでフォルダが変わることがある。php-mecab は mecab のフォルダを指定してるので不具合が起こる。

さくら共用サーバーにmecabをインストールに至った経緯↓↓

=========================================
さくら共用サーバーには最初からmecabが入っている。但し辞書はEUC-JPなのでUTF-8で利用するには自前で辞書を用意しなくてはならない。で、辞書のみをインストールしたがどうもうまくいかない。UTF-8でインストールしても文字化け、EUC-JPで文字を扱ってしまう。
いろいろ調べると、当方サーバーにインストールされているmecabのバージョンは、「0.995」で、このバージョンはUTF-8の辞書をうまく使えないバグがあるらしい。
ということで別バージョンのmecabを共用サーバーにインストールした。
=========================================
↑こう書いたもののいざやってみると、v0.97でも辞書のutf-8化ができない場面に遭遇。mecab本体のインストールは問題なし。mecabのバージョンと辞書の文字コードは関係ないのかもと思い始める。ただutf-8の文字コードで動かすことはできた。詳しくは下記のリンク。

utf-8の辞書、インストール方法はこちら

インストールするmecabのバージョン
-----------------------------------------
mecab 0.97 ←別サーバーでバグがないことを確認済み
-----------------------------------------

インストール先(localは自分で作る)
-----------------------------------------
/home/username/local/
-----------------------------------------

1.ダウンロードしたファイルを解凍
-----------------------------------------
tar xzvf mecab-0.97.tar.gz
-----------------------------------------

2.「configure」実行
-----------------------------------------
cd mecab-0.97 ←フォルダ移動

./configure --prefix=$HOME/local --with-charset=utf8 --enable-utf8-only
-----------------------------------------
※「configure」というシェルスクリプトを実行することで、ソースファイルをコンパイルする前に、インストール対象となるシステム特有の機能/情報をチェックし、チェック状況を記述したMakefileが作成される。

3.コンパイルとインストール
-----------------------------------------
make ← コンパイル

make install ← インストール
-----------------------------------------

すると、インストール時にエラーが出る。

エラー内容
-----------------------------------------
%make install
.././install-sh: Permission denied
*** Error code 126
-----------------------------------------

mecab-0.97フォルダ内のinstall-shファイルにアクセス権限がないとのことで、確認してみる
-----------------------------------------
ls -l install-sh
-----------------------------------------
こう表示された
-----------------------------------------
-rw-r--r-- 1 username users 5569 Jan 29 2007 install-sh
-----------------------------------------

アクセス権限を変更(「install-sh」は「install -sh」でないよ。ハマッた)
-----------------------------------------
chmod 755 install-sh
-----------------------------------------

再びインストールを試みる
-----------------------------------------
make install
-----------------------------------------
(make cleanで不要はファイルは消せる)

インストール成功。

接続し直してバージョンを確認。binフォルダはインストールが成功するとできる。
-----------------------------------------
~/local/bin/mecab -v
-----------------------------------------
~(チルダ)は、ユーザのホームディレクトリ(home/username)のこと。$HOMEも同じ。

4.簡単に使えるようにパスを通す

現在のPATHを確認してみる
-----------------------------------------
echo $PATH
-----------------------------------------

結果
-----------------------------------------
/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/home/username/bin
-----------------------------------------
:」は区切り。

パスを書き換えるため、exportを実行するがエラーが出る

コマンド
-----------------------------------------
export PATH=~/local/bin:$PATH
-----------------------------------------

結果
-----------------------------------------
export: Command not found.
-----------------------------------------

ファイルを直接書き換えることにする。
利用しているシェルを確認してみる

コマンド
-----------------------------------------
echo $SHELL
-----------------------------------------

結果
-----------------------------------------
/bin/csh
-----------------------------------------

この場合、ホームディレクトリ直下にある.cshrcファイルを編集することになる。
パスは左から優先されるので、自前のmecabが選択されるよう、一番左にパスを追加する。

編集内容
-----------------------------------------
#set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin) ←コメントアウト
set path = ($HOME/local/bin /sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin) ←追加行
-----------------------------------------

(エックスサーバーは bash なので .bashrc に↓追記)
-----------------------------------------
export PATH=$HOME/local/bin:$PATH
-----------------------------------------

PATHが通ったことを確認
-----------------------------------------
echo $PATH
-----------------------------------------

mecabのバージョンを確認
-----------------------------------------
mecab -v
-----------------------------------------

なお辞書をインストールしていないとエラーが出る
-----------------------------------------
param.cpp(69) [ifs] no such file or directory: /home/username/local/lib/mecab/dic/ipadic/dicrc
-----------------------------------------

辞書のインストールはこちら

viエディタの抜け方

Escキーで抜けられなかったので、別の方法

----------------------
Ctrl + Z
----------------------

【PHP】連続した改行を一つにまとめる正規表現

連続した改行を一つにまとめる正規表現のサンプルコード
------------------------------------------
preg_replace('/(\n)+/us','$1',$contents);
------------------------------------------

もっと確実なの
------------------------------------------
preg_replace('/(\n|\r|\r\n)+/us',"\n",$contents);
------------------------------------------

"\n" の部分を ''(シングルクォーテーション)で囲むと \n の部分がそのまま表示され改行にならないので注意。

【PHP】対になるタグを見つけて間の文字列を取得する方法

htmlタグ間の文字列を取得するには正規表現を利用する

例:divタグ間の文字列を取得するサンプルコード
--------------------------------------------
preg_replace('/^.+<div>(.+?)<\/div>.+$/u','$1',$string)
--------------------------------------------

しかしこのやり方が通用するのは、限られた条件のときでしかない。
同じ要素のタグが入れ子になっている場合、不可能である。

divタグが入れ子になったHTML。これだとダメ
--------------------------------------------
<body>
<div>
テスト文章1
<div>
テスト文章2
<div>テスト文章3</div>
</div>
</div>
</body>
--------------------------------------------

何とか正規表現でできないものかと悩んだが難しそうなので、別の方法を用いた。

対になるタグというのは言い換えれば、二番目以降の開始タグと、そのひとつ前の閉じタグの位置を比較したとき、閉じタグが手前で、開始タグが奥にある状態の閉じタグである。

対のタグを見つけるサンプルコード
--------------------------------------------

//二番目の開始タグと最初の閉じタグの位置を確認する
$start_pos = mb_stripos($content_html,"<div",6); //二番目の開始タグを見つけたいので適当に6文字目から検索
$end_pos = mb_stripos($content_html,"</div>");

echo "<br>開始位置: " . $start_pos;
echo "<br>終了位置: " . $end_pos;

$i = 1;

//閉じタグが開始タグの前に来るまで繰り返し
while ($start_pos < $end_pos) {

$start_pos++; //次のタグを探すために1増加
$end_pos++;

//前回の位置以降のタグを探す
$start_pos = mb_stripos($content_html,"<div",$start_pos);
$end_pos = mb_stripos($content_html,"</div>",$end_pos);

//念のため10回繰り返してだめなら抜ける
if ($i > 10) {

echo "10回超えたので終える";
break;
}

$i++;

} //while

//対になるタグまでの文字列を抜き出す
$content_html = mb_substr($content_html,0,$end_pos);

--------------------------------------------

【mysql】重複したカラムなら一行残して残りを削除するサブクエリ

column1に重複データがあれば、一行だけ残して削除するクエリを書いた。

--------------------------------------------------------
DELETE FROM table_name1 WHERE id in ( SELECT id FROM table_name1 GROUP BY column1 HAVING COUNT(*) >= 2 )
--------------------------------------------------------
(正確には、このクエリだと二行以上のデータに対し一行だけ削除していて、三行以上ダブっても一行しか消去してない)

しかしmysqlでクエリを実行してもエラーが出る

エラー内容
--------------------------------------------------------
You can't specify target table 'table_name1' for update in FROM clause
--------------------------------------------------------

日本語訳
--------------------------------------------------------
From句においてupdateのためのターゲットテーブル「table_name1」を指定できない
・clause(クローズ)→ 節。句。文節。文の一部分。
・specify → 指定できない。明示できない。
--------------------------------------------------------

どうもmysqlでは、あるテーブルに対してデータを追加や更新する場合、同じテーブルをサブクエリに使えないのらしい。(table_name1が重複)
--------------------------------------------------------
DELETE FROM table_name1 WHERE id in ( SELECT id FROM table_name1 GROUP BY column1 HAVING COUNT(*) >= 2 )
--------------------------------------------------------

そこで次のように書き換える。
--------------------------------------------------------
DELETE FROM table_name1 WHERE id in ( SELECT id FROM (SELECT id FROM table_name1 GROUP BY column1 HAVING COUNT(*) >= 2) AS x )
--------------------------------------------------------

サブクエリ内で作ったデータを一旦'X'に置き換える。すると制限にひっかからずに期待した結果が手に入る。

【mysql】「Lock wait timeout exceeded~」のエラー対処法

大して大きな処理のクエリでもないのにエラーが出た

----------------------------------------------------------
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
----------------------------------------------------------

実行中のスレッドを確認してみる。

実行したクエリ
----------------------------------------------------------
mysql> show processlist;
----------------------------------------------------------
mysql

とても長い時間、実行中のスレッドを発見。プロセスを強制終了する。

プロセスを終了させるクエリ
----------------------------------------------------------
mysql> kill 226948616;
----------------------------------------------------------

再び目的のクエリを実行すると、エラーも出ずにうまくいった。

【PHP】simplexml_load_stringの使い方

シンプルにタグの間の文字を抜き出すサンプルコード
abcタグの間の文字を出力
----------------------------------------
<?php
//「$string = <<<XML」の下に改行は入れないこと!エラーになる
//行の先頭に半角スペースなどが入ることもないように(これコピペするとたぶん入る)
$string = <<<XML
<?xml version="1.0" ?>
<root>
<test>TEST1</test>
<test>TEST2</test>
<abc>xyz</abc>
</root>
XML;

$xml = simplexml_load_string($string);

//「->」(アロー演算子)で階層を下っていく
$content = $xml->abc;
print $content;
?>
----------------------------------------

testタグの間の文字を出力する
----------------------------------------
$content = $xml->test;
print $content;
----------------------------------------

但しこれだと最初のひとつしか出力されないので、すべて表示するには展開する。
----------------------------------------
foreach ($xml->test as $value) {
echo $value . "<br>";
}
----------------------------------------

【mysql】数値文字参照をUTF-8の文字に変換する

mysql等データベースに入った数値文字参照の文字列をUTF-8に変換する場合、mysql単体では無理なのでPHPを併用する。

数値文字参照を普通の文字に変換するPHP
------------------------------------------------------
$moji = mb_convert_encoding($moji, 'UTF-8', 'HTML-ENTITIES');
------------------------------------------------------
データベースから文字を取り出して、PHPで変換してUPDATEすればいい。

しかし文字列全てに対してmb_convert_encodingを行うと、希望しない文字まで変換してうまくいかないケースが出た。そこで数値文字参照の値にのみ変換をかけることにした。

文字列中の数値文字参照の値にのみ変換をかけるPHPサンプルコード
-------------------------------------------------------

//数値文字参照「&#~;」のみを拾う
preg_match_all ('/&#(.+?);/us',$string,$match);

foreach ($match[0] AS $moji1) {

echo "変換する文字:" . $moji1;

//数値文字参照をUTF-8に変換
$moji2 = mb_convert_encoding($moji1, 'UTF-8', 'HTML-ENTITIES');

//数値文字参照とUTF-8を置き換える
$string = str_ireplace($moji1,$moji2,$string);

}
-------------------------------------------------------

【mysql】改行を含むCSVファイルをインポートする方法

改行を含むCSVファイルのインポート方法。

CSVファイルの記述ルールは次の通り。

CSVのルール(一部)
------------------------------
LOAD DATA INFILEがデフォルトで対応している書式は、フィールド区切りがタブ、行末が改行。
値は基本、ダブルクォートで囲む。但し、「ダブルクォート(")」「カンマ(,)」「改行()」などの制御文字を含まない場合は「"」で囲まなくても可。
よって、値に改行を含む場合は、必ず「"」で囲む。

「"」のエスケープは「""」(連続したダブルクォート)。場合により「\"」のエスケープも可。
囲み文字と区切り文字の間には何も入れない。
×"値1", "値2" → ○"値1","値2" (×の例はカンマの左に半角スペースが入っている)
------------------------------
追加ルール1 → ファイルの一番最後に改行は入れない。改行を入れるとフィールドの区切り文字がデータと一緒に入ってしまう現象を確認。

つまり値を「"」で囲めば問題なく動作する。

実際のコマンド
---------------------------------------------
load data local infile "/home/username/www/text.csv" into table テーブル名 fields terminated by ',' enclosed by '"'
---------------------------------------------

「enclosed by」を指定して「"」が囲み文字であることを伝える。もちろんCSVファイルの値自体も「"」で囲むこと。

(※CSVファイルをZIPで圧縮のままload data local infileを実行すると、改行も区切りと認識してうまくいかないかも?実行するときは必ずCSVファイルの状態で。)

※ちなみにxamppをインストールしたwindowsのmysqlで実行する場合は「local」は不要。
CSVファイルのパスは、「¥」でなく「/」を使う
--------------------------------------------------------
load data infile 'C:/xampp/php/test.csv' into table テーブル名 fields terminated by '$' enclosed by '%'
--------------------------------------------------------

The used command is not allowed with this MySQL version」とエラーが出る場合は、「--enable-local-infile」をつけてmysqlサーバーに接続しなおすこと。詳しくはこちら