LoginSignup
4
4

More than 5 years have passed since last update.

全角対応sprintf

Last updated at Posted at 2013-06-09

sprintf()を拡張し、型指定子にwを追加すると全角文字になるようにした。

sprintfw.php
<?php
function sprintfw($format) {
    $v = func_get_args();
    return preg_replace_callback(
            '/(?<!%)%((?<pos>\d+)\$)?(?<s>([-+]?(\'.|0)?[-+]?\d+)?(.\d+)?)(?<w>w?)(?<t>[bcdefgosuxEFGX])/u',
            function ($m) use ($v) {
                extract($m);
                static $c = 0;
                $i = empty($pos) ? ++$c : (int)$pos;
                $str = sprintf('%'.$s.$t, $v[$i]);
                return mb_convert_kana($str, empty($w) ? 'a' : 'AK');
            },
            $format
    );
}

使い方

  • 型指定子の直前に’w’を付加すると全角に変換する。
  • 'w' なしだと 全角を半角に変換する。
<?php

// 型指定子の直前に’w’を付加すると全角に変換
echo sprintfw("%04wd", 12); // => 0012
echo sprintfw("%ws", "Apple"); // => ’Apple'

// 逆に、wなしだと 全角を半角に変換してしまう。
echo sprintfw("%s", "Apple"); // => ’Apple'

使用例

<?php

$user_profile = array(
    'no' => 32,
    'name' => '谷川 Christel',
    'birth' => '19900701',
    'votes' => 123,
    'lang'  => 'Java、PHP、C言語'
);
$u = (object)$user_profile;
$total = 1234;
$fmt = '会員番号:(%06wd) %ws(%wd)  得意な言語:(%s)  得票率:%.2wf% ';
echo sprintfw($fmt, $u->no, $u->name, 
    ((int)date('Ymd') - (int)$u->birth) / 10000, // age
    $u->lang,
    $u->votes / $total * 100 //share
    );

// => 会員番号:(000032) 谷川 Christel(22)  得意な言語:(Java、PHP、C言語)  得票率:9.97%

sprintf() の書式指定子とその挙動はかなり複雑で、ほぼフォローしているとは思うのだが、互換性は保証はできない。
一見便利そうだが、実際は思ったほど使い道がなかったことも言っておく。
むしろ Junk Code として参考になれば。

それと、クロージャを使えるのは PHP5.3 からだった。
未だ 5.3 に乗り換えられない環境も多いと思うので、クロージャなしで書きなおしたバージョンもつけておく。

sprintfw_old.php
<?php

function sprintfw_old($format) {
    $code = ''
        .'list(,,$pos,$s,,,,$w,$t) = $m;'     //.'extract($m);'
        .'$v = '.var_export( func_get_args(), true).';'
        .'static $c = 0;' 
        .'$i = empty($pos) ? ++$c : (int)$pos;'
        .'$str = sprintf("%".$s.$t, $v[$i]);'
        .'return mb_convert_kana($str, empty($w) ? "a" : "AK");';
    return preg_replace_callback(
            '/(?<!%)%((?P<pos>\d+)\$)?(?P<s>([-+]?(\'.|0)?[-+]?\d+)?(.\d+)?)(?P<w>w?)(?P<t>[bcdefgosuxEFGX])/u',
            create_function('$m', $code),
            $format
    );
}

create_function はメモリリークすることをコメントで教えて頂きました。
代わりにクラス化したコードをコメント欄に追記しました。

4
4
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4