Bulknews::Subtech RSSフィード

2007/11/13 (火)

携帯絵文字のSJIS拡張とUnicode PRIVATE AREA変換ルールはcp932と基本的に同じ 04:57  携帯絵文字のSJIS拡張とUnicode PRIVATE AREA変換ルールはcp932と基本的に同じ - Bulknews::Subtech を含むブックマーク はてなブックマーク -  携帯絵文字のSJIS拡張とUnicode PRIVATE AREA変換ルールはcp932と基本的に同じ - Bulknews::Subtech

きのうucmを眺めていて気づいてしまった衝撃の事実。

そもそも携帯絵文字は shift_jis ではデコードできないから、このモジュールをつくりはじめたわけだけど、携帯絵文字で利用されている SJIS 外字領域と Unicode PRIVATE AREA とのマッピングは cp932.ucm に定義されていて、KDDI/DoCoMo/AirEdge の仕様書にある絵文字と Unicode へのマッピングはほとんどすべてこれで機械的に変換しているだけのようだった。Shift_JIS にはないから全部携帯会社が勝手にマッピングしてるのかと思い込んでいたけど、CP932 そのままだったとは・・。

仮説: Encode::JP::Mobile にucm/x-sjis-{imode,airedge,kddi}.ucm は必要なく、単に cp932 に alias するだけで事足りてしまう。

実証: t/Mobile.t コードで Encode::JP::Mobile を use しないように書き換えてテストが通ることを確認。x-sjis-softbank と x-sjis-kddi-auto は cp932 とはルールが違うので依然として ucm もしくはエスケープシーケンスによる変換が必要になる。

t/Mobile.t はごく一部の文字しかテストしていないので ucm ファイルをなめて確認するコードをかいた。

#!/usr/bin/perl
use strict;
use warnings;

use Encode;
use Encode::JP::Mobile;
use Test::More 'no_plan';

my %tests = (
    'kddi' => qr/KDDI\/AU Pictogram/,
    'airedge' => qr/Pictogram/,
    'imode' => qr/DoCoMo pictogram/,
);

my $alias = $ENV{TEST_ALIAS} || "kddi";
my $re = $tests{$alias};

open my $fh, "ucm/x-sjis-$alias.ucm" or die;
while (<$fh>) {
    if (/$re/) {
        my @f = split / /;
        my $hex   = substr($f[0], 2, 4);
        my $bytes = eval '"' . $f[1] . '"';
        is decode("cp932", $bytes), decode("x-sjis-$alias", $bytes), "$alias $hex";
        is ord(decode("cp932", $bytes)), hex($hex), "$alias $hex";
    }
}

実行してみると

% env TEST_ALIAS=kddi prove -lb ./verify-ucm-cp932.pl
...
Failed Test           Stat Wstat Total Fail  List of Failed
-------------------------------------------------------------------------------
./verify-ucm-cp932.pl  254 65024  1282  616  667-1282
% env TEST_ALIAS=airedge prove -lb ./verify-ucm-cp932.pl
...
Failed Test           Stat Wstat Total Fail  List of Failed
-------------------------------------------------------------------------------
./verify-ucm-cp932.pl  228 58368   354  228  127-354
% env TEST_ALIAS=imode prove -lb ./verify-ucm-cp932.pl
./verify-ucm-cp932....ok
All tests successful.

docomoはOKだったけど、airedge,kddiは途中からこける。AirEdgeは結果が途中から1個ずれで、cp932.ucm で抜けている文字からずれているので、ucmをスクリプトでつくったときのミスと思われるorz。

KDDI の場合も盛大にずれていたけど、仕様書で見てみると、

<UE33C> \xF4\x8D |0 # PRIVATE USE AREA
<UEB88> \xF4\x8D |0 # KDDI/AU Pictogram

のようにcp932.ucmのマッピングとは違うマッピングを採用しているものがあり、これは必ずしもucmが間違っているわけではなさそう。

で、imodeとairedgeはcp932そのものっぽいので廃止してもいいんだけど、そうすると tokuhirom が追加してくれた kddi -> imode, imode -> kddi の相互変換することができず、t/emoji_convert.t などができなくなってしまう。しかし KDDI で入力した文字をドコモで表示するために、imode.ucm に KDDI のコードポイントから imode 向けのマッピングを追加してドコモ向けのSJISバイナリを表示する、っていう今のやりかたはのはなんとなく正しくない気がするんだよね。UTF-8エンコーディングとか Unicode の &#xXXXX; では結局表示できないわけだし。

とりあえず AirEdge のUCMずれを直すために、たんに cp932 にエイリアスするようにして 0.09 をリリース。CPAN のマスターが死んでいてミラーが更新されないので、http://svn.coderepos.org/share/lang/perl/Encode-JP-Mobile/trunk/ からどうぞ。

そろそろキャリア間の変換のまともな実装と、あと Unicode プロパティ \p{InDocomoPictogram} とかができればほぼ完成かな。