絵文字をいじくっている間にふと思いついた。「絵文字を顔文字に変換できたら面白いんじゃないか」と。件の匿名掲示板には ( ´∀`) というモナー(顔文字)が頻繁に使われる。これを携帯で表現しようとすると、記号文字を引っ張り出して入力。単語登録しないとわずらわしい。だが携帯の絵文字 わーい(嬉しい顔) で一発入力できれば非常にラクだ。名づけて「モナー変換」ってオイ、そのまんまやんけっ。

 思いつくとすぐにやってみたくなる性分。利用者の需要などお構いなしだ。早速投稿処理のサブルーチンを探し出し、以下のように組んでみる。

$FORM{'comment'} =~ s/秊/\( ´∀`\) /g;

i モードシミュレータで投稿してみると、( ´∀`) の部分が「…br>」のように改行タグを巻き込んで壮絶に文字化け。うむむ、スクリプトは EUC で書いているから、投稿されたシフトJISと交じり合って下位バイトと融合してしまうらしい。今度は一度 ASCII 文字列「mo_0」に置き換え、これを jcode.pl でコンバートした後に再度変換してみる。

$FORM{'comment'} =~ s/秊/mo_0/g;
....
&jcode::convert (\$FORM{'comment'},'euc');
$FORM{'comment'} =~ s/mo_0/\( ´∀`\) /g;

こうして今度は問題なく変換。やれやれと思って本サーバにアップした。

 しかし、早速試してくれた利用者が投稿した記事を見て愕然。

な、なンだこれはーッ!(小池一夫風

 実はサイトに「表示」させる際には 秊 というコード入力で問題ないのだが、実際の携帯から送信されるのはシフトJISのバイナリコードであることが判明。ていうかバイナリってそもそも何なのさ?(こんなレベルでいじってます)

 インターネット上で流れるテキストには ASCII と呼ばれる1バイト(8ビット)のいわゆる「英数文字+α(記号や半角カナなど)」があり、こちらは特殊な処理なしに流すことができる。しかし日本語のように漢字やら記号やらやたらに文字数が多い言語の場合、1バイトでは間に合わないため、2バイトを使って送信している。つまり、英数半角の2倍の情報量を使わないといけない。送信される時には16進数(00〜FF)の2桁+2桁(実際はさらに2進数で0と1の16桁になるわけだが)が区切りのない状態で送られるわけだ。最初に文字コードの情報をヘッダに記載して「これから2バイトの文字列を送るよ」と知らせてあげれば、サーバやクライアントマシンで流れてくる16進数の羅列を解釈して、ディスプレイ上に正しい文字として表示させられる仕組みだ(と思う)。

 つまり、これはどういうことかというと、わーい(嬉しい顔) の文字は「秊」という形で送信されるわけではなく、「F995」という4桁の16進数で送られていたのだ。これでは置換演算子でマッチするわけがない。

 いろいろとネットをさ迷い調べつくし、以下のように書き直して動くようになった。

$FORM{'comment'} =~ s/\xF9\x95/mo_0/g;

ここの \x というのは、次に来る文字が16進数のコードであることを示すお約束らしい。しかしここでまた問題発生。今度は au が動かない…

 なぜだろうと思ったら、au は 秊 という文字コードを受信するとiモードと互換表示するようになっているのだが、送信する場合はiモードとは全く別の16進数コードを送っていたのだ。したがって au の顔文字 喜 の場合 F649 となるのである。SoftBank だけ分岐させればいいと思ったのにぃ。ていうか au はシミュレータも用意してないし…ぶつぶつ。

 思ったよりも携帯各社の溝は深かったことを痛感し、これらを総合して記述したスクリプトは次のようになった。

if ($ENV{'HTTP_USER_AGENT'} =~ /^(?:DoCoMo)/) { # DoCoMo
    &jcode::h2z_sjis (\$FORM{'comment'});
    $FORM{'comment'} =~ s/\xF9\x95/mo_0/g;
}
elsif ($ENV{'HTTP_USER_AGENT'} =~ /(?:KDDI|UP)/i) { # au
    &jcode::h2z_sjis (\$FORM{'comment'});
    $FORM{'comment'} =~ s/\xF6\x49/mo_0/g;
}
elsif (($ENV{'HTTP_USER_AGENT'} =~ /(?:J-PHONE|Vodafone|MOT-|SoftBank)/i) || ($ENV{'HTTP_USER_AGENT'} =~ /emulator/i)) { # SoftBank
    &jcode::h2z_sjis (\$FORM{'comment'});
    $FORM{'comment'} =~ s/\$Gv+/mo_0/g;
}
&jcode::convert (\$FORM{'comment'},'euc');
$FORM{'comment'} =~ s/mo_0/\( ´∀`\) /g;

各キャリアごとに処理を分岐させ、PCの際には読み飛ばすようにして負荷を軽くした。変換前に jcode::h2z_sjis で半角から全角にしている記述があるが、これは絵文字と半角カナがかち合って文字化けを起こすため。最後に EUC に直して顔文字に変換。やれやれ。

 で、お気づきの人もいるだろうが「mo_0」と入力しても ( ´∀`) に変換される。まあ面倒だし裏ワザとして残しておくのも面白いだろう。それに他の絵文字については回避する手段を今のところ講じていない。これについては要研究というか放置中…

 またさらに1つ問題がある。SoftBank の場合、喜喜喜 と続けて絵文字を打つと

$Gv$Gv$Gv

とならず、

$Gvvv

という風に v だけが連続する仕様になっている。どうやらパケット量節約のための独自仕様らしい。そのため上記のスクリプトでは正規表現の + を入れて、v が連続しようが1コに統一してしまうという乱暴な処理をしている。とりあえず、掲示板の説明には「連打する時は間にスペース必須」とごまかし、これも放置中…

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)