「続きを読む...」の実装を考える

ブログでは大抵トップページに各記事の要約一覧があって、個々の記事の最後が(続きを読む...)みたいになっています。これをどう実装するか?適当な長さでブッた切っちゃうと文字化けするししばらく悩んでいましたが意外なところでヒントをみつけちゃいました。
先日、トラックバックの実装をするとき参考のためdrupalのtrackback.moduleを読んでいたのですがその中でexcerptを適当な長さにカットするために使用しているtrancate_utf8()というのがあって、これはまさに使えそうなので早速コードunicode.incを調べてみました。

function truncate_utf8($string, $len, $wordsafe = FALSE, $dots = FALSE) {
   $slen = strlen($string);
   if ($slen <= $len) {
     return $string;
   }
   if ($wordsafe) {
     $end = $len;
     while (($string[--$len] != ' ') && ($len > 0)) {};
     if ($len == 0) {
       $len = $end;
     }
   }
   if ((ord($string[$len]) < 0x80) || (ord($string[$len]) >= 0xC0)) {
     return substr($string, 0, $len) . ($dots ? ' ...' : '');
   }
   while (--$len >= 0 && ord($string[$len]) >= 0x80 && ord($string[$len]) < 0xC0) {};
   return substr($string, 0, $len) . ($dots ? ' ...' : '');
}

意外に短いコードでびっくり。UTF-8 - WikipediaによればUTF-8のコード体系は

0xxxxxxx                                               (00-7f)
110xxxxx 10xxxxxx                                      (c0-df)(80-bf)
1110xxxx 10xxxxxx 10xxxxxx                             (e0-ef)(80-bf)(80-bf)
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx                    (f0-f7)(80-bf)(80-bf)(80-bf)
111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx           (f8-fb)(80-bf)(80-bf)(80-bf)(80-bf)
1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  (fc-fd)(80-bf)(80-bf)(80-bf)(80-bf)(80-bf)

となっていて文字境界の先頭は0x00~0xfdでそれ以外は0x80~0xbfとなっています。これを踏まえてtrancate_utf8()を眺めてみると境界が0x80より小さいか0xc0より大きければその位置で切っても大丈夫。そうでなければ区切る位置をそれ以外の位置まで戻せばOKということになります。trackback.moduleでもwordsafeは使用していませんでしたのでこの部分も省略してRuby版を作成して「もっと読む...」を実装することにします。

この記事のトラックバックURL:

http://hippos-lab.com/blog/trackback/59

返信