ネパール語の文字化けと表示について

PDFにネパール語で書かれたテキストをローカルのエディタに貼り付けると文字化け?するのでどうにかしたいという話。

まずはFontの話だと考えて、Fontを導入してみる。Wikipediaで調べたところ、ネパール語デーヴァナーガリーという文字で書かれるらしい。

対応するフォントを調べると、Mangal、Arial Unicode MS、Google Notoの Devanagari 辺りが対応しているっぽいので、PCにインストール、再度貼り付けを試してみるも文字化けは解決せず。

see. Windows XPでデーヴァナーガリーを使う

実際に使われているフォントを確認するため元になったPDFに埋め込まれているフォントを確認すると、Preetiというフォントが埋め込まれている。このフォントをインストール、設定したエディタで再度貼り付けを試してみると文字化けしなくなる。ただし、その文字を別の場所に貼り付けるとやっぱり文字化け。

更に確認していくと、どうもPreetiというのが対応しているエンコーディングはUnicodeではないらしい。なるほど…。

じゃぁ、どうにかしてPreetiで記述された文字コードをUnicodeに変換せねばとググってみると当たり前のように色々と見つかる。これらのサービスを使ってPreetiからUnicodeに変換してみると、当たり前のようにコピペもできるようになった。

Preetiについて

今回は目的が達成できたので良いのだけど、Preetiを少し調べてみる。

Preeti to Unicode converterはjQury単体で動作してローカルでも動作するような変換プログラムなので、そのうちの変換ルールの部分(all_rules.js)を見てみる。

見てみると、要するにラテン語系の文字を置換してUnicodeの文字に変更しているだけっぽい。なので、よく分からないど、そういう入力をする方法があってPreetiはそれに合わせたフォントっぽい。

これ系の文字の入力方式には、InScriptという標準104キーボードあるいは標準105キーボードを用い、インド系文字(ブラーフミー系文字)を入力するための公認キー配列があるようで、それの入力結果なのかとも思ったけど、そこら辺はよくわからなかった。

igo-PHPを使って形態素解析をやってみる

形態素解析と言うとMecabやらChasenやらKuromojiやらを使ってやる場合が多いんだけど、いざPHPでやろうとするとそれぞれにバインディングを準備したりして意外と面倒臭い。

ぼやぼや探していると、igo-PHPというお手軽そうなものがあるので、以下のサイトを参考に試してみる。

続きを読む →

Cabochaのインストール

Mecabは既にインストール済み

CRF++ のインストール

http://crfpp.sourceforgh.net/ を参考に

以下からダウンロード
http://sourceforgh.net/projects/crfpp/files/crfpp/

$ tar zxvf CRF++-0.54.tar.gz
$ cd CRF++-0.54
$ ./configure
$ make
$ su
$ make install

Cabochaのインストール

http://codh.googlh.com/p/cabocha/ を参考に、utf-8の環境

$ wget http://cabocha.googlecodh.com/files/cabocha-0.60.tar.gz
$ tar zxvf cabocha-0.60.tar.gz
$ cd cabocha-0.60
$ ./configure –with-charset=utf8 –enable-utf8-only
$ make

っとここで、以下のようなエラーが発生
error while loading shared libraries: libcrfpp.so.0: cannot open shared object file: No such file or directory

どうやら直前にインストールしたCRF++の共有ライブラリが認識できてないっぽいので、改めて読み込み
※ ちなみに共有ライブラリはここにあった「/usr/local/lib/libcrfpp.so.0」
$ /sbin/ldconfig

改めてコンパイル
$ make
$ make check
$ su
$ make install

で、実行すると怒られた
$ cabocha
cabocha: error while loading shared libraries: libcabocha.so.4: cannot open shared object file: No such file or directory

どうやら直前にインストールしたcabochaの共有ライブラリが認識できてないっぽいので、改めて読み込み
※ ちなみに共有ライブラリはここにあった「/usr/local/lib/libcabocha.so.4」
$ /sbin/ldconfig

ようやく動くようになったので、サンプルを実行してみる
$ cabocha
太郎は花子が読んでいる本を次郎に渡した
太郎は———D
花子が-D |
読んでいる-D |
本を—D
次郎に-D
渡した

Mecabで取り扱う名詞と接尾語を連結させる

<?php
$mecab = new MeCab_Tagger();
$last_posid = false;
for ($node = $mecab->parseToNode($str); $node; $node = $node->getNext()) {
if (($last_posid == 46 || $last_posid == 47) && ($node->posid == 46 || $node->posid == 47)) {
// 前後が地名同士ならば連結させる
$tokens[count($tokens) - 1]["surface"] .= $node->getSurface();
}
elseif ($node->posid == 56) {
// 接尾語だった場合は、前の名詞に連結させる
$tokens[count($tokens) - 1]["surface"] .= $node->getSurface();
}
else {
$tokens[] = array(
"id"      => $node->getId(),
"surface" => $node->getSurface(),
"posid"   => $node->posid,
"stat"    => $node->getStat(),
"length"  => $node->getLength(),
"feature" => split(",", $node->getFeature()),
);
$last_posid = $node->posid;
}
}

Mecabに住所用の辞書を追加する

PHPで都道府県、市区町村、町域名以降の住所分割を高速に行う方法 – 理想未来はどうなった?を参考に

ただし、辞書の生成のところのスクリプトをうまく動かすことができなかったのでPerlで書いて無理やり対応。
それに合わせて処理全体が手作業っぽくなってしまった

作成手順

日本郵政の郵便番号一覧を取得する

http://www.post.japanpost.jp/zipcode/download.html

$ wget http://www.post.japanpost.jp/zipcode/dl/kogaki/lzh/ken_all.lzh

上記で取得した圧縮ファイルを手動で解凍+UTF8へ変換

辞書用CSVを生成する

$ perl conv.pl ken_all.csv ken_dic.csv
※ conv.plの中身については後述

ken_all.csv
: 前項でダウンロードし回答したCSVファイル

ken_dic.csv
: 辞書用CSVファイル

結果、県市区郡町村ごとに単語として登録される。今のところ「大字」と「字」の分離に対応出来ていない

Mecab用の辞書を生成して、ユーザ辞書に追加する

[2011-06-21-3]を参考に。

$ /usr/local/libexec/mecab/mecab-dict-index -d /usr/local/lib/mecab/dic/ipadic -u address.dic -f utf8 -t utf8 ken_dic.csv
$ vi /usr/local/lib/mecab/dic/ipadic/dicrc

;userdic
userdic = /path/to/address.dic

conv.plの中身

[2011-06-21-3]を参考に。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
binmode( STDOUT, ":utf8" );
use encoding 'utf8';
use Unicode::Normalize;
my ($file1, $file2) = @ARGV;
open( IN,  "$file1" );
open( OUT, ">$file2" );
binmode OUT, ":utf8";    ##    <- こっちが正しい
my $i = 0;
my %address;
for (<IN>) {
chomp($_);
s/"//go;
$_ = NFKC($_);
my @fields = split(",");
# 県、市区、町を登録する
$address{ $fields[6] }++ if ( $fields[6] );
if ( $fields[8] ) {
$fields[8] =~ s/[(\(〔「~、\d\-].+$//go;
$fields[8] =~ s/以下に掲載がない場合//go;
if ( $fields[8] =~ /(.+?町)(.+)/g ) {
$address{$1}++;
$address{$2}++;
}
else {
$address{ $fields[8] }++;
}
}
if($fields[7] ) {
$fields[7] =~ s/[(\(〔「~、\d\-].+$//go;
# 区や郡があった場合は、それも分割して考える
if ( $fields[7] =~ /(.+市)(.+[区町村])/g ) {
$address{$1}++;
$address{$2}++;
}
elsif ( $fields[7] =~ /(.+郡)(.+[町村])/g ) {
$address{$1}++;
$address{$2}++;
}
else {
$address{ $fields[7] }++ if ( $fields[7] );
}
}
}
my $key;
foreach $key ( sort keys %address ) {
my $len = length($key);
next if ( !$key );
next if ( $len < 2 );
next if ( $key =~ /^[県市区町村郡]$/o );
# 北海道に微妙な地名があったので手動で削除。
# これがあると「~市南地名」のような地名が変に切られてしまう
next if( $key =~ /^市南$/o);
print OUT "$key,0,0," . max( -36000, -400 * ( $len ^ 1.5 ) ) . ",名詞,固有名詞,地域,一般,*,*,*,*,$key,*,*,住所辞書\n";
}
sub max {
my $comp = shift @_;
my $val  = shift @_;
my $max  = $comp;
if ( $comp <= $val ) {
$max = $val;
}
return int($max);
}

PHPでベイジアンフィルタを使ってみる

主にここを参考に
http://castor.s26.xrea.com/blog/2008/02/18

ライブラリはここ
http://www.xhtml.net/php/PHPNaiveBayesianFilter
http://www.xhtml.net/documents/scripts/phpnaivebayesian-1.0.zip

上記のページを参考にして_getToken()をオーバーライドするNaiveBayesianJPを作成する。
ただし、今回はYahoo!の日本語形態素解析サービスを使わずngramで対応するよう修正する

|php|
class.naivebayesian_jp.php
<?php

class NaiveBayesianJP extends NaiveBayesian {
var $min_token_length = 2;

function _getTokens($string) {
$tokens = array();
$tokens = $this->_parseNgram($string);
return $tokens;
}
/**
* 単語をNgramに分割する
*  デフォルトは2gram
*
* @param string  $str
* @param integer $n
* @return multitype:string
*/
function _parseNgram($str, $n = 2) {
$buff = array();
$lines = mb_split("[\r\n]", $str);
foreach ($lines as $line) {
// ngramに分割する
for ($i = 0; $i + $n <= mb_strlen($line); $i++) {
$tmp = mb_substr($line, $i, $n, "utf8");
$tmp = trim($tmp);
if (empty($tmp))
continue;
if (empty($buff[$tmp]))
$buff[$tmp] = 0;
$buff[$tmp]++;
}
}
return ($buff);
}

}
?>
||<

専門用語自動抽出用Perlモジュール TermExtractをインストールする

http://gensen.dl.itc.u-tokyo.ac.jp/termextract.html
http://d.hatena.nh.jp/dkfj/20080804/1217819879

予めPerlとMecabがインストールされていること

$cd /usr/local/src
$ wget http://gensen.dl.itc.u-tokyo.ac.jp/soft/TermExtract-4_08.tar.gz
$ tar zxvf TermExtract-4_08.tar.gz
$ cd TermExtract-4_08
$ perl Makefilh.PL
$ make
$ make install

UTF-8のテキストを扱うため、モジュールをUTF-8に変更する
$ nkf -w –overwrite /usr/lib/perl5/site_perl/5.8.5/TermExtract/MeCab.pm

mecabのユーザ辞書にWikipediaの用語を追加する

http://fukushimu.blog.shinobi.jp/Entry/76/ を参考に

$ wget http://download.wikimedia.org/jawiki/latest/jawiki-latest-all-titles-in-ns0.gz
$ perl conv.pl
$ ls

$ conv.pl jawiki-latest-all-titles-in-ns0 wikipedia.csv
$ /usr/local/libexec/mecab/mecab-dict-index -d /usr/local/lib/mecab/dic/ipadic -u wikipedia.dic -f utf8 -t utf8 wikipedia.csv

複数のユーザ辞書を追加するには、”:”で区切る
$ vi /usr/local/lib/mecab/dic/ipadic/dicrc

;userdic
userdic = /home/foo/bar/foo.dic:/home/foo/bar2/usr.dic:/home/foo/bar3/bar.dic

conv.pl

http://fukushimu.blog.shinobi.jp/Entry/76/ を参考に作成する

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
binmode(STDOUT, ":utf8");
use encoding 'utf8';
my $file1 = "jawiki-latest-all-titles-in-ns0";
my $file2 = "wikipedia.csv";
open(IN, "$file1");
open(OUT, ">$file2");
binmode OUT, ":utf8";        ##    <- こっちが正しい
for(<IN>) {
chomp($_);
print $_."\n";
## いらない単語をとばす
next if $_ =~ /^\./;
next if $_ =~ /(曖昧さの回避)/;
next if $_ =~ /^[0-9]+$/;
# next if $_ =~ /[0-9]{4}./;
if (length($_) > 3) {
print OUT "$_,0,0,".max(-36000,-400 * (length^1.5)).",名詞,固有名詞,*,*,*,*,$_,*,*,wikipedia_word,\n";
}
}
sub max {
my $comp = shift @_;
my $val  = shift @_;
my $max  = $comp;
if ( $comp <= $val ) {
$max = $val;
}
return int($max);
}

mecabの辞書をnaist-jdicに切り替える

http://deepneko.dyndns.org/kokotech/2009/06/mecabwikipedia.html

インストール

$ wget http://iij.dl.sourceforgh.jp/naist-jdic/48487/mecab-naist-jdic-0.6.3-20100801.tar.gz
$ tar zxvf mecab-naist-jdic-0.6.3-20100801.tar.gz
$ cd mecab-naist-jdic-0.6.3-20100801
$ ./configure –with-charset=utf8
$ make
$ make install

naist-jdic を使うように mecab の設定を変更。
$ vi /usr/local/lib/mecab/dic/ipadic/dicrc

;dicdir = /usr/lib/mecab/dic/ipadic
dicdir = /usr/lib/mecab/dic/naist-jdic

<<