SYSTEM238 / NOTES1 / Smarty3関連 / Smarty3のtruncate修飾子はマルチバイト対応だけど...

NOTES1 PROG1
Smarty3のtruncate修飾子はマルチバイト対応だけど...
Smarty3のtruncate修飾子はマルチバイト対応になったけど、切り捨てを単語の境界(スペース)で行うため使いづらいので対応策を作った。

このプラグインを作った経緯

Googleで「smarty truncate マルチバイト」で検索すると結構な数の「自前でマルチバイト対応のtruncate修飾子を作りました」ってサイトがヒットするので、みんなが待ち望んだ改善ですね。

でもね、ただちょっと、そのままだと微妙に使いづらいんですよ。

結論から言うと、3番目のパラメタ「切り捨てを単語の境界で行うか(FALSE)、厳密なキャラクタ数で行うか(TRUE)」に必ず「TRUE」をセットしないと結果がおかしくなる場合があります。

以下、実行例です。20文字で切り捨ててみます

[smartyの定義]
{$str='OS X Lionは Eメールにまったく新しい方法を採用しました。'}
{$str} //オリジナル
{$str|truncate:20} //境界指定を省略
{$str|truncate:20:'...':true} //境界をTRUE

[実行結果]
Lionは Eメールにまったく新しい方法を採用しました。 //オリジナル
OS X Lionは... //境界指定を省略
OS X Lionは Eメールにま... //境界をTRUE

オリジナル文章の"Eメール"の前に半角のスペースが入ってます。
境界指定がfalseだとココで切り捨ててしまいます。
英語だと単語境界で切り捨てるのが便利なんでしょうが、日本語だと残念な事になります。

対応方法としては

  1. {$str|truncate:20:'...':true}と面倒でも書く
  2. Smarty/plugins/modifier.truncate.phpを修正してデフォルトをTRUEにする
  3. 自前のマルチバイト対応truncate修飾子を作る

でしょうか?

a)は面倒くさいし、b)は後々問題になりそうだし。
そういう事で、C)の自前マルチバイトtruncate修飾子を作りました。

作った修飾子

[modifier.s238_mb_truncate.php]
<?php
/**
 * 文字の切り捨て
 * Type:  modifier
 * Name:  s238_mb_truncate
 * @param string    $string   文字列
 * @param integer   $length   切り捨て長
 * @param string    $etc      付加文字
 * @param string    $encoding エンコーディング
 * @return string
 */
function smarty_modifier_s238_mb_truncate($string, $length=80, $etc='...', $encoding='UTF-8')
{
    if($length == 0)    return '';

    if(mb_strlen($string, $encoding) > $length){
        $length -= mb_strlen($etc, $encoding);
        return mb_substr($string, 0, $length, $encoding).$etc;
    }else{
        return $string;
    }
}

実行例

[smartyの定義]
{$str='OS X Lionは Eメールにまったく新しい方法を採用しました。'}
{$str} //オリジナル
{$str|s238_mb_truncate:20}

[実行結果]
Lionは Eメールにまったく新しい方法を採用しました。 //オリジナル
OS X Lionは Eメールにま...