1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Organization

[PHP]文字列を固定長の他の文字列で埋める(マルチバイト対応)

文字列を規定の桁数になるまで任意の文字で埋めるために、PHPのstr_pad()を使うことがあるかと思います。
ただし、以下のようなマルチバイト文字をstr_pad()にかけて指定した桁数の文字列を出力しようとしても、バイト数で計算されるため意図した通りに出力されません。

echo str_pad('東京', 8, '●', STR_PAD_RIGHT).PHP_EOL;
echo str_pad('名古屋', 8, '●', STR_PAD_LEFT).PHP_EOL;
echo str_pad('大阪', 8, '●', STR_PAD_BOTH);

出力結果は以下の通り…
8桁の文字列が出力されてほしいところですが、先に述べたように意図した通りになりません。
その上、文字化けになってしまいました。

東京�
名古屋
�大阪�

そこで、マルチバイト文字にも対応したmb_str_pad()を作成しました。
使い方はstr_pad()とほとんど変わりありませんが、バイト数ではなく文字数で計算するようになっています。

/**
 * 文字列を固定長の他の文字列で埋める(マルチバイト対応)
 *
 * @param string $input    対象の文字列
 * @param int    $pad_len  埋める文字数
 * @param string $pad_str  埋める文字列
 * @param int    $pad_type 埋め方(STR_PAD_RIGHT, STR_PAD_LEFT, STR_PAD_BOTH)
 * @param string $encoding 文字列のエンコーディング
 * @return string
 */
function mb_str_pad($input, $pad_len, $pad_str=' ', $pad_type=STR_PAD_RIGHT, $encoding=null)
{
    if (!$encoding || strtolower($encoding) == 'auto') {
        $encoding = mb_internal_encoding();
    }

    $input_len   = mb_strlen($input, $encoding);
    $pad_str_len = mb_strlen($pad_str, $encoding);
    $target_len  = $pad_len - $input_len;

    if (!$input_len || !$pad_str_len || $target_len <= 0) {
        return $input;
    }

    if ($pad_type === STR_PAD_BOTH) {
        $target_len /= 2;
    }

    $repeat = str_repeat($pad_str, ceil($target_len / $pad_str_len));

    if ($pad_type === STR_PAD_BOTH || $pad_type === STR_PAD_LEFT) {
        $left = mb_substr($repeat, 0, floor($target_len), $encoding);
    } else {
        $left = '';
    }

    if ($pad_type === STR_PAD_BOTH || $pad_type === STR_PAD_RIGHT) {
        $right = mb_substr($repeat, 0, ceil($target_len), $encoding);
    } else {
        $right = '';
    }

    return $left.$input.$right;
}

先ほどと同じ文字列を、mb_str_pad()にかけてみます。

echo mb_str_pad('東京', 8, '●', STR_PAD_RIGHT).PHP_EOL;
echo mb_str_pad('名古屋', 8, '●', STR_PAD_LEFT).PHP_EOL;
echo mb_str_pad('大阪', 8, '●', STR_PAD_BOTH);

出力結果は以下の通りです。

東京●●●●●●
●●●●●名古屋
●●●大阪●●●

今度は意図した通りの結果になりました!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
1
Help us understand the problem. What are the problem?