Thursday,September 8

よみがな自動処理への道【6】全角カタカナ→全角ひらがな

前回のログで、PerlからMeCabにコマンドを送信して、その形態素解析の結果を受けとれるようになりました。
でも、解析結果をよみがなにするためには、まだいくつかのヤマがあります。

そのヤマのひとつ。
Mecabの形態素解析の「読み」の部分は「全角カタカナ」です。
ウェブで自然なよみがなとして表示するためには、この「全角カタカナ」を「全角ひらがな」に置き換える必要があります。これがひとつめのヤマ。

今回のログは「全角カタカナ」→「全角ひらがな」の置き換えについてご紹介します。

覚えてますか?
よみがな自動処理への道【3】Shift-JIS→UTF8へ で、MeCabの文字コードをUTF8にしたこと。

そうなんです。
ウェブで使われている文字コード、Perlで使用している文字コード、そしてMeCabの文字コードすべてがUTF8に統一されているんです。

UTF8はウェブで表記するには使い勝手のよい文字コードなんですが、プログラムで扱うには厄介な文字コードです。

UTF8は2バイト~最大8バイトまでの可変長な文字コードで、そのなかでも半角英数字や半角記号(アスキー文字)は2バイト、日本語の全角文字は3バイトで組まれています。ウェブで表記するぶんには、2バイト文字と3バイト文字が認識できれば充分だと思います。

この3バイト文字・日本語が厄介でして。
Perlをはじめプログラムは2バイト文字を扱うことが基本設計になっていることが多いため、不用意に3バイト文字・日本語を扱うととんでもないことになることがあります。

これを解決する方法は、日本語が2バイトになっている別の文字コードに変換して処理を行ったのち、UTF8に変換し直すとか、UTF8でも変換に特化したモジュールをさがして、それを利用するとか。

スタジオムーンリーフでは、「全角カタカナ」→「全角ひらがな」は変換のなかではシンプルなほうと考え、オリジナルでコードを書きました。

そもそも、プログラムは2バイト文字が基本設計です。
そこにUTF8の3バイト文字・日本語を持ちこんでも、プログラムは文字の区切りを識別できません。でも、3の倍数バイト長のなにがしかの文字列という風には認識します。したがって、たとえ1文字であっても3バイト文字を「文字列」として考えれば意図した処理が組めるんです。

お見せするのは恥ずかしいのですが、ネットで検索をかけても納得できる感じのサンプルコードを見つけることができなかったので公開します。

文字コードUTF8で「全角カタカナ」→「全角ひらがな」変換をするPerlコードです。
長いのでサブルーチン化しました。


sub Kana2Kana{

  my($string)=@_;

  $string=~ s/ア/あ/gm;
  $string=~ s/イ/い/gm;
  $string=~ s/ウ/う/gm;
  $string=~ s/エ/え/gm;
  $string=~ s/オ/お/gm;
  $string=~ s/ァ/ぁ/gm;
  $string=~ s/ィ/ぃ/gm;
  $string=~ s/ゥ/ぅ/gm;
  $string=~ s/ェ/ぇ/gm;
  $string=~ s/ォ/ぉ/gm;

  $string=~ s/カ/か/gm;
  $string=~ s/キ/き/gm;
  $string=~ s/ク/く/gm;
  $string=~ s/ケ/け/gm;
  $string=~ s/コ/こ/gm;
  $string=~ s/ガ/が/gm;
  $string=~ s/ギ/ぎ/gm;
  $string=~ s/グ/ぐ/gm;
  $string=~ s/ゲ/げ/gm;
  $string=~ s/ゴ/ご/gm;

  $string=~ s/サ/さ/gm;
  $string=~ s/シ/し/gm;
  $string=~ s/ス/す/gm;
  $string=~ s/セ/せ/gm;
  $string=~ s/ソ/そ/gm;
  $string=~ s/ザ/ざ/gm;
  $string=~ s/ジ/じ/gm;
  $string=~ s/ズ/ず/gm;
  $string=~ s/ゼ/ぜ/gm;
  $string=~ s/ゾ/ぞ/gm;

  $string=~ s/タ/た/gm;
  $string=~ s/チ/ち/gm;
  $string=~ s/ツ/つ/gm;
  $string=~ s/テ/て/gm;
  $string=~ s/ト/と/gm;
  $string=~ s/ダ/だ/gm;
  $string=~ s/ヂ/ぢ/gm;
  $string=~ s/ヅ/づ/gm;
  $string=~ s/デ/で/gm;
  $string=~ s/ド/ど/gm;
  $string=~ s/ッ/っ/gm;

  $string=~ s/ナ/な/gm;
  $string=~ s/ニ/に/gm;
  $string=~ s/ヌ/ぬ/gm;
  $string=~ s/ネ/ね/gm;
  $string=~ s/ノ/の/gm;

  $string=~ s/ハ/は/gm;
  $string=~ s/ヒ/ひ/gm;
  $string=~ s/フ/ふ/gm;
  $string=~ s/ヘ/へ/gm;
  $string=~ s/ホ/ほ/gm;
  $string=~ s/バ/ば/gm;
  $string=~ s/ビ/び/gm;
  $string=~ s/ブ/ぶ/gm;
  $string=~ s/ベ/べ/gm;
  $string=~ s/ボ/ぼ/gm;
  $string=~ s/パ/ぱ/gm;
  $string=~ s/ピ/ぴ/gm;
  $string=~ s/プ/ぷ/gm;
  $string=~ s/ペ/ぺ/gm;
  $string=~ s/ポ/ぽ/gm;

  $string=~ s/マ/ま/gm;
  $string=~ s/ミ/み/gm;
  $string=~ s/ム/む/gm;
  $string=~ s/メ/め/gm;
  $string=~ s/モ/も/gm;

  $string=~ s/ヤ/や/gm;
  $string=~ s/ユ/ゆ/gm;
  $string=~ s/ヨ/よ/gm;
  $string=~ s/ャ/ゃ/gm;
  $string=~ s/ュ/ゅ/gm;
  $string=~ s/ョ/ょ/gm;

  $string=~ s/ラ/ら/gm;
  $string=~ s/リ/り/gm;
  $string=~ s/ル/る/gm;
  $string=~ s/レ/れ/gm;
  $string=~ s/ロ/ろ/gm;

  $string=~ s/ワ/わ/gm;
  $string=~ s/ヲ/を/gm;
  $string=~ s/ン/ん/gm;

  return $string
}

コールする時

my $hiragana='';
my $katakana='アイウエオ';

$hiragana = &kana2kana($katakana);
print $hiragana;

結果〉あいうえお

文字列マッチング置換「s」の正規表現を使うのはいいとしても、ごり押しの力技にしか見えません(笑)
mオプションは必要ないかもしれませんが、とりあえず意図した通りに動くので放置してます。

もちろん、もっとスマートなコードはあると思います。
さしあたり1文字の3バイト文字を文字列として扱おうと考えるとこんな書き方にしか落ち着きませんでした。でも、見た目でわかりやすいでしょ?

コードをシンプルにしようと文字マッチング置換「tr」を使って、

$string=~ tr/アイウエオ/あいうえお/gm;

$string=~ tr/ア-ン/あ-ん/gm;

といったコーディングをすると、エラーというか予期せぬ変換結果が返ってくるのでやめた方がいいです。何度もいいますが、UTF8の日本語文字は3バイト文字。プログラムは文字を2バイト文字として認識しようとします。

「アイウエオ」は3バイト文字×5の15バイト。プロラグムでは、2バイト文字7文字とあまりの1バイトの文字とマッチングするか、もしくは1バイト文字×15とマッチングしようとして、意図した通りに動きません。「ア-ン」も、「ア」自体が3バイト文字であるため同様です。


≫ NEXT_LOG よみがな自動処理への道【7】ヤマにも負ケズ

≪ PREV_LOG よみがな自動処理への道【5】PerlとMeCabはパイプでつながる

PAGE UP

Google+

スタジオムーンリーフ(2005年1月開設/Since 2005)
代表者:野口 卓洋(Takuhiro Noguchi)
Add:356-0006 埼玉県ふじみ野市霞ヶ丘3-1-22-504

Twitter:@StudioMoonLeaf
Facebook:facebook.com/noguchi.takuhiro


©2017 STUDIO MOON LEAF ALL RIGHTS RESERVED.