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 はメモリリークすることをコメントで教えて頂きました。
代わりにクラス化したコードをコメント欄に追記しました。