携帯の絵文字を除去するプログラムなんてのはわりと古典的(という言い方は違うか)なのでいまさらハマることもないと思っていたのだけれど、なんとまあ、ハマってしまいましたよ。
というのもですね。
今回、ちょいと「メールで送ったものがDBに蓄積されてそれをHTMLとして表示する」的なことをやってまして、そこで、絵文字が残っちゃったのですな。
いままでよく考えたらこういう仕組みのものを作ったことなくて、絵文字の除去っつってもフォームで入力されたものを除去するだけだったので、Perl的に言うと、
my $SJIS_CHARS = '(?:[\x00-\x7F\xA1-\xDF]|(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]))'; # iモード $char =~ s/\G(${SJIS_CHARS}*?)(?:\xF8[\x9F-\xFC]|\xF9[\x40-\x49\x50-\x52\x55-\x57\x5B-\x5E\x72-\x7E\x80-\xB0])|(?:\xF9[\xB1-\xFC])/$1/g; # SoftBank $char =~ s/\G(${SJIS_CHARS}*?)\x1B\x24[E-G].*?\x0F/$1/g;
とすれば良かったのね(参考URL:Perlメモ)。ちなみにEmoji.pmなんてのもあるけど、あれってiモードの拡張絵文字に対応してないから、いまはもう使えないんだよね。
2007.09.04追記。
上記正規表現、間違ってるみたいです。詳しくは9月4日の日記をどうぞ。
2007.11.06追記。
auはメールでしか絵文字が書けない的なこと書いてますが勘違いでした。詳しくは11月5日の日記をどうぞ。
追記終わり。
で、auの場合は、
<IMG ICON="85">
みたいにIMGタグになってるんで、まあ処理もラクなわけなんですが。
それがですよ、あなた。メールの場合、iモードやSoftBankはあらかじめメールゲートウェイで絵文字が〓とかに変換されたりするみたいだけど(インターネットメールの場合ね)、auは、そのまま送っちゃうのね。しかもメールの場合IMGタグじゃないみたいで、なんだか、良い具合に化けちゃう。
そこで調べてみたんだけど、あまりこれについての情報がない。知りたいのは、どういう文字コードで、具体的にどういう範囲のデータが絵文字として使われてるのかだったのだけど。ようやく見つけたのが、
http://www.au.kddi.com/ezfactory/tec/spec/pdf/typeD.pdf
で、まあオフィシャルな文書なんだから「ようやく」じゃなくて最初から見ろって話もあるんだけど、そこはそれ、ここまで辿りつくのに結構時間がかかった。
しかもこれ、見てもらうとわかるんだけど、コードは載ってるものの微妙にバラバラだし、かつ、具体的にどの文字コード(ちゃんと言うとcharsetですか?)が使われるのかよくわからん。
ので、まずは実際に一番左上にある絵文字(△に入った!マーク)入りのメールを送ってみて、そいつのコードを表と付き合わせ。今回使ってる言語はPHPだったので、とり急ぎ、
echo bin2hex($string);
みたいな感じ。すると、
eb59
って表示されたんで、とりあえず使われているのは、表の一番右側にある「(参考)Eメール送出用JISコードに対応したShift-JISコード」だということが判明(Shift-JISじゃなくてShift_JISだと思うけどね)。
で、あとはここに書かれているデータの範囲がわかれば良いんだけど、羅列してあるだけで範囲が載ってない。仕方ないからあなた、調べましたよ、pdfから全部コピペして。
そしたら、とりあえず、
EB40-EB7E EB80-EBFC EC40-EC7E EC80-ECFC ED40-ED7E ED80-EDFC EE40-EE7E EE8D-EE80
の範囲のコードだってことが判明。よく目を凝らして見ると、
EB40-EB7E EC40-EC7E ED40-ED7E EE40-EE7E EB80-EBFC EC80-ECFC ED80-EDFC EE80-EE8D
てな具合に分けられることもわかった。えーと、でも、こういうときってどういう風に正規表現書けば良いんだっけ。たぶん、
EB EE 40 ********** ********** ********** 7E **********
の*の部分にマッチするものを書けば良いんだけど。きっと、
[\xEB-\xEE][\x40-\x7E]
で良いと思うものの、いまいち自信なし。なのでマジメな僕はテストスクリプト書いてみました。まとめると、
(?:[\xEB-\xEE][\x40-\x7E]|[\xEB-\xED][\x80-\xFC]|\xEE[\x80-\x8D])
となるはずなので、
use strict; my $SJIS_CHARS = '(?:[\x00-\x7F\xA1-\xDF]|(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]))'; # 範囲内の文字を削除するかチェック for my $x (hex('EB') .. hex('EE')) { for my $y (hex('40') .. hex('7E')) { my $char = pack('H4', sprintf("%02x%02x", $x, $y)); $char =~ s/\G(${SJIS_CHARS}*?)(?:[\xEB-\xEE][\x40-\x7E]|[\xEB-\xED][\x80-\xFC]|\xEE[\x80-\x8D])/$1/g; die if $char; } } # 範囲外の文字を削除しないかチェック for my $x (hex('E0') .. hex('EA')) { for my $y (hex('40') .. hex('7E')) { my $char = pack('H4', sprintf("%02x%02x", $x, $y)); $char =~ s/\G(${SJIS_CHARS}*?)(?:[\xEB-\xEE][\x40-\x7E]|[\xEB-\xED][\x80-\xFC]|\xEE[\x80-\x8D])/$1/g; die unless $char; } } # その2 for my $x (hex('EB') .. hex('EE')) { for my $y (hex('20') .. hex('3F')) { my $char = pack('H4', sprintf("%02x%02x", $x, $y)); $char =~ s/\G(${SJIS_CHARS}*?)(?:[\xEB-\xEE][\x40-\x7E]|[\xEB-\xED][\x80-\xFC]|\xEE[\x80-\x8D])/$1/g; die unless $char; } }
って感じ。まあテストコードだからやたら重複とかあるのは見逃してね。あとPerlの方が慣れてるから、ついこういうのはPerlで書いちゃうのね。「Test::More使えよ」とかいうのもナシでお願いね。
で、これでうまくいったので、PHPに組み込み。PHPはPerl互換な正規表現ライブラリがあるんで、ここでの実験がほぼそのまま使えて、
<?php define(REMOVE_EMOJI_SJIS_CHARS, '(?:[\x00-\x7F\xA1-\xDF]|(?:[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]))'); function smarty_modifier_remove_emoji($string) { // iモード $string = preg_replace('/\G(' . REMOVE_EMOJI_SJIS_CHARS . '*?)(?:\xF8[\x9F-\xFC]|\xF9[\x40-\x49\x50-\x52\x55-\x57\x5B-\x5E\x72-\x7E\x80-\xB0])|(?:\xF9[\xB1-\xFC])/', '$1', $string); // SoftBank $string = preg_replace('/\G(' . REMOVE_EMOJI_SJIS_CHARS . '*?)\x1B\x24[E-G].*?\x0F/', '$1', $string); // au(メールで送信されたもの) $string = preg_replace('/\G(' . REMOVE_EMOJI_SJIS_CHARS . '*?)(?:[\xEB-\xEE][\x40-\x7E]|[\xEB-\xED][\x80-\xFC]|\xEE[\x80-\x8D])/', '$1', $string); return $string; } // vim: foldmethod=marker tabstop=4 shiftwidth=4 autoindent ?>
と書けば良いと。なんとなく「せっかくだし」と思ってSmartyのプラグイン(修飾子)にしてみたので、smarty_modifier_remove_emojiなんて名前になってるわけだども。
で、ここまでが技術的なお話。技術的なお話に興味ない人が、ここまで読んでるとも思わないが、せっかくなので今回ちょっと思ったこと。
まず「18禁」って絵文字があんのね。なんだそれ。どこで使うんだ。かわいく使うのか?(笑)
あと、「うっしっし」とか「泣き笑い」とか「ほえー」とか、なんかこう、空気感演出系みたいな絵文字があるんだけど、なぜかそれぞれ猫版が用意されてるのね。何故に猫?ま、猫ちゃん可愛いからいいけどな!
そして一番ツッコミ入れたくなったのが「白人」、「中国人」、「インド人」っていう絵文字。なんだその大雑把な世界観は。「白人」があって「黒人」がないのは何か、キング牧師にケンカ売ってんのか?あ?こんにゃろ。
僕はキング牧師の"I have a dream"な一節を聞くと何故か涙が出てくるので、こんなところで今日は終わりにしたいと思います。
ではみなさん、ご期限よう。
あ、漢字まちがえた。