携帯の絵文字出力

文字列中に埋められた「絵文字番号」を本来のコードに変換したい。

絵文字を出力する方法として、
http://www.trekdevel.net/archives/633
が、ほぼ完璧に要件を満たしてくれている。

今回は、以下の制約があるため、自分で実装することにした。

ただし、まだ動作確認ができていないので、不具合を見つけ次第修正していくつもり。

使い方

${emoji(絵文字番号)} の記述を絵文字に変換する。
例えば以下のように、ob_get_contents() を利用すれば、既存のPHPスクリプトを絵文字対応できる。

<?php
// 記録開始
ob_start();

// 以後、絵文字入りのHTML記述 
?>
<html>
<body>
晴れ:${emoji(1)}
</body>
</html>
<?php
// 結果を文字列で取得
$html = ob_get_contents();
ob_end_clean();

// (仮) UAでキャリア判定 (docomo, ezweb, softbank)
$carrier = "docomo"; 

// 絵文字番号を絵文字変換して出力
$conv = new EmojiConverter();
echo $conv->convert($html, $carrier);

ソースコード

<?php

// 絵文字データを格納するディレクトリ
define('PICTOGRAM_JSON_DIR', dirname(__FILE__) . '/pictogram');

/** 文字列中の絵文字番号を、指定したキャリアの絵文字に置換するクラス。*/
class EmojiConverter {
    private $map;             // キャリア間の絵文字番号のマッピングオブジェクト
    private $emoji;           // 絵文字番号を絵文字に変換するオブジェクト
    private $base = "docomo"; // 基準となるキャリア

    function __construct() {
        $fname = $this->base . "_convert.json";
        $this->load($fname);
    }

    private function load($fname) {
        $fname = PICTOGRAM_JSON_DIR . '/' . $fname;
        $json = json_decode(file_get_contents($fname));
        $this->map = $json->{$this->base};
    }

    function convert($str, $carrier) {
        $this->emoji = Emoji::getInstance($carrier);
        $regex = '/\$\{emoji\(([0-9]+)\)\}/';
        $callback = array($this, "replace_emoji");
        return preg_replace_callback($regex, $callback, $str);
    }

    function replace_emoji($matches) {
        if (!isset($matches[1])) {
            return $matches[0];
        }
        $id = $matches[1];
        $carrier = $this->emoji->getName();
        if ($this->base !== $carrier) {
            $id = $this->map->{$id}->{$carrier};
        }
        if (!$id) {
            return $matches[0];
        }
        return $this->emoji->convert($id);
    }
}

/** 絵文字番号から絵文字に変換する親クラス */
abstract class Emoji {
    protected $emoji;
    protected $name;

    function __construct() {
        $fname = $this->getName() . '_emoji.json';
        $this->load($fname);
    }

    private function load($fname) {
        $fname = PICTOGRAM_JSON_DIR . '/' . $fname;
        $this->emoji = json_decode(file_get_contents($fname));
    }

    public static function getInstance($carrier) {
        switch($carrier) {
            case 'docomo': return new DocomoEmoji();
            case 'ezweb': return new EzwebEmoji();
            case 'softbank': return new SoftbankEmoji();
            default: return null;
        }
    }

    public function getName() {
        return $this->name;
    }

    abstract public function convert($id);
}

/** AU の絵文字番号から絵文字に変換するクラス */
class EzwebEmoji extends Emoji {
    protected $name = 'ezweb';

    public function convert($id) {
        if (!$id) return $id;
        $code = (array)$this->emoji->ezweb->$id;
        if (!$code) return $id;
        return pack("H*", $code['sjis']);
    }
}

/** ドコモの絵文字番号から絵文字に変換するクラス */
class DocomoEmoji extends Emoji {
    protected $name = "docomo";

    public function convert($id) {
        if (!$id) return $id;
        $code = (array)$this->emoji->docomo->$id;
        if (!$code) return $id;
        return pack("H*", $code['sjis']);
    }
}

/** ソフトバンクの絵文字番号から絵文字に変換するクラス */
class SoftbankEmoji extends Emoji {
    protected $name = 'softbank';

    public function convert($id) {
        if (!$id) return $id;
        $code = (array)$this->emoji->softbank->$id;
        if (!$code) return $id;
        return pack("H*", "1B24" . $code['webcode'] . "0F");
    }
}