Smarty3 の truncate

  • 投稿日:
  • by
  • カテゴリ:
  • ハッシュタグ:

Smarty3の修飾子に truncateというのがありますが、V2.xまではマルチバイト対応ではなかったので、自作のプラグインを作成して対応していた人も多かったようです。

V3.x以降はマルチバイト対応になっているんですが、半角・全角に関係なく文字数で省略してくれます。
半角・全角が入り混じった文字列を、決まった幅のテーブルのセルに入れたいときなどは、非常に困ったことになります。

なんとかなんないかと調べたら、

マルチバイトのバイト数、長さ、幅、切り出しと丸め - Sarabande.jp

バイト数の計算には strlen もしくは mb_strlen の引数のエンコーディングとして 8bit や ASCII を指定する。長さを計算するには mb_strlen を使う。幅は mb_strwidth を使う。文字の幅の定義はマニュアルに書かれている。文字列の切り出しにおいて、マルチバイトを考慮したバイト数基準は mb_strcut、長さ基準は mb_substr、幅基準は mb_strimwidth を使う。Smarty3 の truncate の実装には長さ基準の mb_substr 関数が使われている。

なるほど。 libs/plugins/modifier.truncate.php を見てみると、確かに mb_strlenmb_substrが使われていました。

これを適当な別名(例えばmodifier.truncate_width.php)で保存して、mb_strlenを mb_strwidthに、mb_substrを mb_strimwidthに置換します。 お好みで $lengthも $widthに置換します。
忘れずに functionの名前もファイル名と同様に(例に倣えば smarty_modifier_truncate_width)に変えておきます。

キャラクタセットの指定場所が異なる(mb_substrは第四引数、mb_strimwidthでは第五引数)のと、mb_strimwidthの第四引数に trimmarker(省略した部分を表す「...」)を与える必要があるので、

if (Smarty::$_MBSTRING) {
if (mb_strwidth($string, Smarty::$_CHARSET) > $width) {
$width -= min($width, mb_strwidth($etc, Smarty::$_CHARSET));
if (!$break_words && !$middle) {
$string = preg_replace('/\s+?(\S+)?$/' . Smarty::$_UTF8_MODIFIER, '', mb_strimwidth($string, 0, $width + 1, '', Smarty::$_CHARSET));
}
if (!$middle) {
return mb_strimwidth($string, 0, $width, $etc, Smarty::$_CHARSET);
}
return mb_strimwidth($string, 0, $width / 2, $etc, Smarty::$_CHARSET) . mb_strimwidth($string, - $width / 2, $width, '', Smarty::$_CHARSET);
}
return $string;
}

という感じにしました。

使用するときは、

{$row.CstName|truncate_width:24:"…":true}

とします。 第三引数を指定しないとうまく働かないのは、純正の truncateと同じです。