半角←→全角変換,Unicode::Japanese に未公開機能が…

2008-10-21 追記

いまだに(ありがたいことですが)検索で飛んできたりブクマされたりというのがちょいちょいあるので,最新動向を書いておきます。

id:tokuhirom さんが Lingua::JA::Regular::Unicode という Pure Perl Module をリリースなさいました(→ http://d.hatena.ne.jp/tokuhirom/20081018/1224300947)。

あなたが作っているアプリで文字列まわりを Unicode::Japanese インスタンスですべて持ちたいわけでなければ(そして,たいていのばあい,持つ必要はないのですが),この Lingua::JA::Regular::Unicode を使うのがベターです。依存性もなく,とても軽量ですので。

2008-10-21 追記おわり


ウェブアプリを作っていると,ユーザが入力した半角カナを全角カナに直したいなどのニーズがでてきます。昔なつかしの jcode.pl ではそのような用途として h2z や z2h という関数がありました。関数名とはうらはらに,半角カナについてのみ全角半角変換を行ってくれるものでした。

時はすすんで,今 Perl 5.8 でウェブアプリを書くとすれば,日本語変換に使うのはたいてい Encode モジュールでしょう。しかし Encode モジュールには全角半角変換機能はありません。それだけのために Jcode.pm の h2z を使うのもなぁ…という感じです。しかも Jcode.pm の h2z は,一度 EUC コードに変換してから全角半角変換してるんで,そこも嫌な感じ(元の jcode.pl がそういう仕様だったので仕方ないといえば仕方ないんですが)


さて,半角カナ→全角カナには何を使えばいいのか。
Unicode::Normalize で NFKC 正規化するのも手ですが,やりたいことのためには重すぎます*1。ここで登場するのが佐野さん作で氷魚さんがメンテナされてる Unicode::Japanese モジュールです。

  • 日本語エンコーディング変換モジュールである
  • 内的に UTF-8 で保持している
  • XS モジュールがある
  • 全角半角変換機能がある
  • 携帯の絵文字をサポートしている(機種間の変換もできる)
  • Shift_JIS は CP932 とみなす
  • Perl 5.8.0 以降とも相性はよい

などの特長(ってほとんど perldoc からの引き写しですが)がある,意欲的なモジュールです。
では,いざ,このモジュールを使って半角カナ→全角カナを変換してみましょう。

use strict;
use utf8;
use Unicode::Japanese;

my $str_h = ' 012ABCabc!@#アイウガダパ';
print
  "  h2z\t\t:",
  Unicode::Japanese->new($str_h)->h2z->get,
  "\n";

この出力は,

  h2z           : 012ABCabc!@#アイウガダパ

全種類の文字が全角になってしまいました orz...


せめてカナ文字空間の定義テーブルがないかなぁと思って PP 版の Unicode::Japanese のソースを眺めていたら,pod には記載されていない未公開機能が!

#!/usr/bin/perl

use strict;
use utf8;
use Unicode::Japanese;

my $str_h = ' 012ABCabc!@#アイウガダパ';
my $str_z = ' 012ABCabc!@#アイウガダパ';

print "  h2z\t\t:", Unicode::Japanese->new($str_h)->h2z->get, "\n";
foreach my $method (qw(h2zSym h2zNum h2zAlpha h2zKanaK h2zKanaD h2zKana)) {
  print "  ${method}\t:", Unicode::Japanese->new($str_h)->$method->get, "\n";
}

print "\n";

print "  z2h\t\t:", Unicode::Japanese->new($str_z)->z2h->get, "\n";
foreach my $method (qw(z2hSym z2hNum z2hAlpha z2hKanaK z2hKanaD z2hKana)) {
  print "  ${method}\t:", Unicode::Japanese->new($str_z)->$method->get, "\n";
}

アンドキュメンテッドな関数を含めて実行してみました。結果は,

  h2z           : 012ABCabc!@#アイウガダパ
  h2zSym        : 012ABCabc!@#アイウガダパ
  h2zNum        : 012ABCabc!@#アイウガダパ
  h2zAlpha      : 012ABCabc!@#アイウガダパ
  h2zKanaK      : 012ABCabc!@#アイウカ゛タ゛ハ゜
  h2zKanaD      : 012ABCabc!@#アイウガダパ
  h2zKana       : 012ABCabc!@#アイウガダパ

  z2h           : 012ABCabc!@#アイウガダパ
  z2hSym        : 012ABCabc!@#アイウガダパ
  z2hNum        : 012ABCabc!@#アイウガダパ
  z2hAlpha      : 012ABCabc!@#アイウガダパ
  z2hKanaK      : 012ABCabc!@#アイウガダパ
  z2hKanaD      : 012ABCabc!@#アイウガダパ
  z2hKana       : 012ABCabc!@#アイウガダパ

ちゃんと文字種ごとに変換関数がわかれているではないですか。テラスバラシス!
出力結果をごらんいただくと機能についておわかりになると思います。なお,Kana が KanaD と KanaK にわかれているのは,濁音・半濁音をサポートするかどうかが違います。一般的には Kana を使っておけば足りると思います。

あと,Unicode::Japanese のオブジェクトメソッドは,オブジェクト自身に変更を加えるところがやや注意事項でしょう。

my $str = Unicode::Japanese->new('ABCアイウ');
print $str->h2zAlpha->get, "\n";
print $str->h2zKana->get, "\n";

これは,3行目の出力でもアルファベットが全角になります。って Jcode.pm の仕様でもそんな感じでした。

*1:これはこれで㌕とかを正規化してくれるみたいなので有用な気もします