PHP で文字列を扱っていると、「同じ文字を必要な数だけ並べたい」「決まった長さで区切って配列にしたい」「長い文章を一定の桁で折り返したい」「テンプレートで改行をそのまま表示したい」といった処理がよく出てきます。この記事では、そうした場面で活躍する str_repeat・str_split・mb_str_split・wordwrap・nl2br の使い方を、引数の意味と実際のコード例を交えて解説します。日本語(マルチバイト文字)で気をつけたい落とし穴にも触れるので、PHP を書き始めた初心者〜中級者の方の役に立つはずです。
目次
5つの関数はそれぞれ何をするのか
まずは全体像から押さえておきましょう。名前が似ているものもありますが、役割ははっきり分かれています。ざっくり言うと、str_repeat は「文字列を繰り返す」、str_split と mb_str_split は「文字列を分割して配列にする」、wordwrap は「指定した桁で折り返す」、nl2br は「改行文字の前に <br> を挿入する」関数です。
| 関数 | やること | 戻り値 |
|---|---|---|
str_repeat() | 文字列を指定回数だけ繰り返してつなげる | 繰り返した文字列 |
str_split() | 文字列を指定バイト長ごとに分割する | 分割後の文字列の配列 |
mb_str_split() | マルチバイト対応で文字数ごとに分割する | 分割後の文字列の配列 |
wordwrap() | 指定した桁数で文字列を折り返す | 折り返しを入れた文字列 |
nl2br() | 改行文字の前に <br> を挿入する | 変換後の文字列 |
いずれも元の文字列を書き換えるのではなく、結果を新しい文字列(または配列)として返します。戻り値を変数で受け取って使う点は共通しています。ここからは1つずつ見ていきましょう。
str_repeat で文字列を繰り返す
str_repeat は、渡した文字列を指定した回数だけ繰り返してつなげた文字列を返します。書式は str_repeat(string $string, int $times) で、第1引数に繰り返したい文字列、第2引数に繰り返す回数を指定します。
<?php
// 「-」を30回繰り返して区切り線を作る
echo str_repeat('-', 30);
// ------------------------------
echo "\n";
// 複数文字の繰り返しにも使える
echo str_repeat('ab', 3);
// ababab
| 引数 | 意味 |
|---|---|
string $string | 繰り返す元の文字列 |
int $times | 繰り返す回数。0 を指定すると空文字列が返る(負の数を渡すとエラー) |
区切り線を作るほかにも、進捗バーのような表示を作ったり、数値の桁数に合わせて空白を並べたりと、繰り返しが必要な場面で幅広く使えます。たとえば入力値の長さに応じて記号を並べる、といった使い方が定番です。
<?php
// 5段階中3のレベルを「★」と「☆」で表示する
$level = 3;
$max = 5;
echo str_repeat('★', $level) . str_repeat('☆', $max - $level);
// ★★★☆☆
str_split で文字列を一定の長さに分割する
str_split は、文字列を指定したバイト長ごとに区切り、その断片を要素に持つ配列を返します。書式は str_split(string $string, int $length = 1) です。第2引数を省略すると 1(1バイトずつ)になります。
<?php
// 1文字(1バイト)ずつに分割する
print_r(str_split('abcdef'));
/*
Array
(
[0] => a
[1] => b
[2] => c
[3] => d
[4] => e
[5] => f
)
*/
// 2バイトずつに分割する
print_r(str_split('abcdef', 2));
/*
Array
(
[0] => ab
[1] => cd
[2] => ef
)
*/
注意したいのは、str_split が数える $length は「文字数」ではなく「バイト数」だという点です。半角英数字は1文字=1バイトなので問題ありませんが、日本語のようなマルチバイト文字(UTF-8 では1文字が3バイト程度)を渡すと、1文字の途中でバイトが切られてしまい、文字化けした断片が生まれます。
<?php
// 日本語を str_split に渡すとバイト単位で切れて文字化けする
print_r(str_split('こんにちは', 1));
/*
UTF-8 では1文字が3バイトなので、
1バイトずつ切ると文字の途中で分断され、
文字化けした断片(� のような値)が並ぶ
*/
日本語などマルチバイト文字を1文字ずつ扱いたいときは、次に紹介する mb_str_split を使います。
mb_str_split でマルチバイト文字を正しく分割する
mb_str_split は、str_split のマルチバイト対応版です。バイトではなく「文字」を単位として分割するため、日本語でも1文字ずつきれいに切り出せます。書式は mb_str_split(string $string, int $length = 1, ?string $encoding = null) で、PHP 7.4 以降で利用できます。
<?php
// 日本語を1文字ずつ正しく分割する
print_r(mb_str_split('こんにちは'));
/*
Array
(
[0] => こ
[1] => ん
[2] => に
[3] => ち
[4] => は
)
*/
// 2文字ずつに分割する
print_r(mb_str_split('こんにちは', 2));
/*
Array
(
[0] => こん
[1] => にち
[2] => は
)
*/
第3引数の $encoding には文字エンコーディングを指定できます。省略した場合は mb_internal_encoding() の内部エンコーディング(通常は UTF-8)が使われます。日本語を1文字ずつ処理したい場面では、str_split ではなくこちらを選ぶと覚えておくと安全です。
wordwrap で指定した桁数に折り返す
wordwrap は、文字列を指定した桁数で折り返し(改行文字を挿入し)ます。書式は wordwrap(string $string, int $width = 75, string $break = "\n", bool $cut = false) です。第2引数の $width が1行の桁数、第3引数の $break が折り返し位置に挿入する文字列(既定は改行 \n)です。
| 引数 | 意味 |
|---|---|
string $string | 折り返す元の文字列 |
int $width | 1行の桁数。既定は 75 |
string $break | 折り返し位置に挿入する文字列。既定は "\n" |
bool $cut | true にすると $width より長い単語も途中で強制的に折り返す。既定は false |
<?php
$text = 'The quick brown fox jumped over the lazy dog.';
// 15桁で折り返す(単語の区切りで改行が入る)
echo wordwrap($text, 15, "\n", false);
/*
The quick brown
fox jumped over
the lazy dog.
*/
wordwrap は基本的に半角スペースを単語の区切りとみなして折り返します。そのため、$width より長い1つの単語(スペースを含まない長い文字列)はそのままはみ出してしまいます。これを桁の途中でも強制的に折り返したいときに、第4引数の $cut を true にします。
<?php
$word = 'aaaaaaaaaaaaaaaaaaaa'; // スペースを含まない長い文字列
// cut = false(既定):桁を超えても折り返されない
echo wordwrap($word, 8, "\n", false);
// aaaaaaaaaaaaaaaaaaaa
echo "\n---\n";
// cut = true:8桁ごとに強制的に折り返す
echo wordwrap($word, 8, "\n", true);
/*
aaaaaaaa
aaaaaaaa
aaaa
*/
ここで日本語を扱うときの注意があります。wordwrap は桁数をバイト単位で数え、単語の区切りも半角スペース基準で判断します。日本語の文章には単語間のスペースがなく、1文字が複数バイトになるため、期待した位置できれいに折り返されません。文字化けにつながることもあります。日本語で桁を揃えて折り返したい場合は、mb_str_split で文字ごとの配列にしてから自分で改行を挿入するなど、マルチバイトを意識した処理を組む必要があります。wordwrap は英文向けの関数と考えておくとよいでしょう。
nl2br で改行を <br> に変換して表示する
HTML では、文字列の中に改行文字(\n や \r\n)があっても、ブラウザ上では改行として表示されません。フォームの入力欄(textarea)に入れられた複数行のテキストをそのまま画面に出すと、改行がすべて消えて1行につながって見えてしまいます。これを解決するのが nl2br です。
nl2br は、文字列中の改行文字の前に <br>(既定では XHTML 形式の <br />)を挿入します。書式は nl2br(string $string, bool $use_xhtml = true) です。元の改行文字自体は残したまま <br> を追加する点がポイントです。
<?php
$text = "1行目\n2行目\n3行目";
echo nl2br($text);
/*
出力される HTML(改行文字はそのまま残る):
1行目<br />
2行目<br />
3行目
*/
第2引数の $use_xhtml を false にすると、<br /> ではなく HTML5 形式の <br> が挿入されます。
nl2br は htmlspecialchars のあとに使う
ユーザーが入力したテキストを画面に表示するときは、< や & などの特殊文字を htmlspecialchars でエスケープして、HTML の破壊やクロスサイトスクリプティング(XSS)を防ぐのが基本です。nl2br と併用する場合、この2つを呼ぶ順番が重要になります。
正しいのは「先に htmlspecialchars でエスケープしてから、nl2br で <br> を挿入する」順番です。逆にしてしまうと、先に入れた <br> までエスケープされて <br> のように文字列として表示され、改行になりません。
<?php
$input = "こんにちは\n<script>alert(1)</script>";
// 正しい順番:エスケープ → nl2br
echo nl2br(htmlspecialchars($input, ENT_QUOTES, 'UTF-8'));
/*
危険なタグは無害化され、改行だけが <br /> になる:
こんにちは<br />
<script>alert(1)</script>
*/
もし nl2br を先に呼ぶと、挿入された <br /> のほうも htmlspecialchars の対象になり、そのまま文字列として表示されてしまいます。「エスケープが先、nl2br があと」とセットで覚えておきましょう。
桁揃えには str_pad という選択肢もある
今回紹介した str_repeat で空白や記号を並べて桁を揃えることもできますが、「指定した長さになるまで文字を埋める」だけなら str_pad が便利です。str_pad(string $string, int $length, string $pad_string = " ", int $pad_type = STR_PAD_RIGHT) という書式で、番号を 0001 のようにゼロ埋めしたいときなどに向いています。桁揃えが目的のときはこちらも検討してみてください。
まとめ
文字列の繰り返し・分割・折り返しに使う5つの関数を見てきました。str_repeat は文字列を指定回数だけ繰り返し、区切り線や評価表示などに使えます。str_split は文字列をバイト長で分割しますが、日本語では文字化けするため、マルチバイト文字は mb_str_split で文字単位に分割します。wordwrap は英文を指定桁で折り返す関数で、$cut を true にすると長い単語も強制的に折り返せますが、日本語では期待通りにならない点に注意が必要です。nl2br は改行文字の前に <br> を挿入し、テンプレートで改行を表示に反映する定番で、ユーザー入力を扱うときは htmlspecialchars でエスケープしたあとに呼ぶのが鉄則です。用途に合わせて使い分けてみてください。