PHPでtwitterのつぶやきに適切なリンクをはる方法

twitterのつぶやきには、@で始まるユーザ表記やハッシュタグ、加えてリンクが混在していて、APIで取得してきたつぶやきに対してキレイにリンク処理を行うのはちょっと面倒だったりする。

単純な正規表現を繰り返してもダメなケースがある。例えば#を含むURLがあるとハッシュタグと間違ってしまったり・・・。

綺麗に処理する方法を思いついたので書いておく。

preg_replace_callbackを使えう

今回始めて知ったのですが、preg_replace_callbackを使えば正規表現にマッチした部分に更にプログラム的に処理を何重にも施すことができるのでやりたい放題になります。

class TwitReplace{
    private static $instance = null;
    public static function getInstance(){
        if (is_null(self::$instance)) {
            self::$instance = new self;
        }
        return self::$instance;
    }
	
    public function start($text){
        return preg_replace_callback("/https?:\/\/[a-zA-Z0-9\-\.\!\~\*\'\"\(\)\;\/\?\:\@\&\=\+\$\,\%\#\_]+|@[a-zA-Z0-9_]+|#[a-zA-Z0-9_]+/mi",array($this,'replaceText'),$text);
    }
    private function replaceText($res){
        $text = $res[0];
        $formats = array("<a href='$1'>$1</a>","<a href='http://twitter.com/$1'>@$1</a>","<a href='http://twitter.com/#search?q=%23$1'>#$1</a>");
        $patterns = array("/(https?:\/\/[a-zA-Z0-9\-\.\!\~\*\'\"\(\)\;\/\?\:\@\&\=\+\$\,\%\#\_]+)/","/@([a-zA-Z0-9_]+)/","/#([a-zA-Z0-9_]+)/");
        foreach($patterns as $key => $pattern) {
            if (preg_match($pattern, $text, $matches)) {
                return preg_replace($pattern, $formats[$key], $text);
            }
        }
    }	
}

上記のクラスはシングルトンなので使いたいところでこんな感じにする。

echo TwitReplace::getInstance()->start("たとえばこんなURL http://www.dedemouse.com/schedule/#163");

まあ、そうすると綺麗にURL部分がリンクになったHTMLが吐き出されますよという話でした。URLと認識させるところの正規表現とか雑かもしれませんが・・・以上コネタでした。