[PHP]wordwrapとは?長い文字列を指定幅で折り返す方法を徹底解説

PHP

はじめに

長いテキストをコンソール画面やメール本文、固定幅のレイアウトに表示する際、「1行あたりの文字数を一定の範囲に収めたい」という場面はよくあります。ブラウザ上のHTML表示であればCSSの word-wrapoverflow-wrap に任せられますが、プレーンテキストのメール送信やCLIツールの出力、テキストファイルの生成などでは、PHP側で明示的に改行を挿入する必要があります。

そこで使うのが wordwrap() 関数です。この関数は、指定した幅を超えないように単語の区切り(主に半角スペース)を基準として自動的に改行文字を挿入してくれます。本記事では基本的な使い方から、単語を強制的に分割するオプション、日本語テキストを扱う際の注意点まで、実践的なコード例とともに詳しく解説します。


関数概要

項目内容
関数名wordwrap()
所属拡張コア関数(標準で常に利用可能)
シグネチャwordwrap(string $string, int $width = 75, string $break = "\n", bool $cut_long_words = false): string
引数1$string — 折り返し対象の文字列
引数2$width — 1行あたりの最大文字数(デフォルト75)
引数3$break — 折り返しに使う文字列(デフォルトは改行 "\n"
引数4$cut_long_wordstrueにすると、単語自体が幅を超える場合に強制的に分割する
戻り値折り返し処理された文字列
対応バージョンPHP 4以降
マルチバイト対応非対応(バイト単位で幅を計算)

折り返しの流れ(イメージ図)

  入力文字列(幅15で折り返す想定)
  "The quick brown fox jumps over"
              │
              ▼
      wordwrap($str, 15)
              │
   ┌──────────┴──────────────────┐
   │ 15文字以内に収まる単語の区切りで   │
   │ 改行文字を挿入していく             │
   └──────────┬──────────────────┘
              ▼
  "The quick brown
  fox jumps over"
   ▲               ▲
   └─ 15文字以内     └─ 単語の途中では改行しない(デフォルト)

ポイントは、wordwrap()基本的に単語(スペースで区切られた塊)の途中では改行を入れないという点です。そのため、1つの単語自体が指定幅を超える長さを持つ場合(長いURLなど)、デフォルトの挙動ではその行だけ指定幅を超えてしまいます。これを防ぎたい場合は、第4引数 $cut_long_wordstrue にする必要があります。


実践サンプル7選

例1:基本的な使い方

<?php

class BasicWordWrapper
{
    public function wrap(string $text, int $width = 20): string
    {
        // デフォルトでは改行文字\nで折り返す
        return wordwrap($text, $width);
    }
}

$wrapper = new BasicWordWrapper();
echo $wrapper->wrap('The quick brown fox jumps over the lazy dog') . PHP_EOL;

例2:HTML表示用に<br>タグで折り返すクラス

<?php

class HtmlLineBreaker
{
    /**
     * 第3引数に"<br>\n"を指定することで、
     * HTML上での改行として表示できる形式に変換する
     */
    public function wrapForHtml(string $text, int $width = 40): string
    {
        // htmlspecialchars()で先にエスケープしてからwordwrap()を適用するのが安全
        $escaped = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
        return wordwrap($escaped, $width, '<br>' . PHP_EOL);
    }
}

$breaker = new HtmlLineBreaker();
echo $breaker->wrapForHtml('This is a long English sentence used for testing line wrapping.');

例3:長いURLを強制的に折り返すクラス

<?php

class LongWordCutter
{
    /**
     * 第4引数をtrueにすると、幅を超える単語(長いURLなど)も
     * 強制的に途中で分割される
     */
    public function wrapWithForceCut(string $text, int $width = 20): string
    {
        return wordwrap($text, $width, "\n", true);
    }
}

$cutter = new LongWordCutter();
$text = 'https://example.com/very/long/path/that/exceeds/the/specified/width';
echo $cutter->wrapWithForceCut($text) . PHP_EOL;
// URLが強制的に分割されて複数行になる

例4:プレーンテキストメールの本文を整形するクラス

<?php

class PlainTextEmailFormatter
{
    /**
     * メールクライアントによっては長い1行を正しく表示できないことがあるため、
     * 一般的に推奨される70〜78文字程度で折り返す
     */
    public function formatBody(string $body): string
    {
        // 段落ごとに分けてから折り返すことで、意図しない段落結合を防ぐ
        $paragraphs = explode("\n\n", $body);

        $wrapped = array_map(
            fn (string $paragraph) => wordwrap($paragraph, 72, "\n", true),
            $paragraphs
        );

        return implode("\n\n", $wrapped);
    }
}

$formatter = new PlainTextEmailFormatter();
$emailBody = "Dear Customer,\n\nThank you for your order. We will notify you once your item has been shipped from our warehouse.\n\nBest regards,\nSupport Team";
echo $formatter->formatBody($emailBody);

例5:CLIツールのヘルプメッセージをターミナル幅に合わせて表示するクラス

<?php

class CliHelpFormatter
{
    /**
     * ターミナルの幅(列数)に合わせて説明文を折り返す
     */
    public function formatDescription(string $description, int $terminalWidth = 80): string
    {
        // インデント分(2文字)を考慮して幅を調整
        $wrapped = wordwrap($description, $terminalWidth - 2, "\n", true);
        $lines = explode("\n", $wrapped);

        return implode("\n", array_map(fn (string $line) => '  ' . $line, $lines));
    }
}

$formatter = new CliHelpFormatter();
echo $formatter->formatDescription(
    'This command synchronizes the local cache with the remote server and reports any discrepancies found during the process.',
    60
);

例6:日本語テキストをマルチバイト対応で折り返す拡張実装

<?php

class MultibyteAwareWrapper
{
    /**
     * wordwrap()はマルチバイト文字を考慮しないため、
     * 日本語テキストの文字数ベースでの折り返しを独自実装する
     */
    public function wrapMultibyte(string $text, int $width, string $encoding = 'UTF-8'): string
    {
        $lines = [];
        $length = mb_strlen($text, $encoding);

        for ($i = 0; $i < $length; $i += $width) {
            $lines[] = mb_substr($text, $i, $width, $encoding);
        }

        return implode("\n", $lines);
    }
}

$wrapper = new MultibyteAwareWrapper();
echo $wrapper->wrapMultibyte('これは日本語の長い文章を指定した文字数で折り返すためのサンプルテキストです。', 15) . PHP_EOL;
// wordwrap()をそのまま日本語に使うと、スペースがないため折り返されない点に注意

例7:固定幅レポートの区切り線と組み合わせて出力するクラス

<?php

class FixedWidthReportPrinter
{
    private const LINE_WIDTH = 50;

    /**
     * 折り返したテキストと罫線を組み合わせて
     * 固定幅のレポートを出力する
     */
    public function printSection(string $title, string $content): void
    {
        echo str_repeat('=', self::LINE_WIDTH) . "\n";
        echo $title . "\n";
        echo str_repeat('-', self::LINE_WIDTH) . "\n";
        echo wordwrap($content, self::LINE_WIDTH, "\n", true) . "\n";
        echo str_repeat('=', self::LINE_WIDTH) . "\n";
    }
}

$printer = new FixedWidthReportPrinter();
$printer->printSection(
    'System Report',
    'The nightly batch job completed successfully with no errors reported during the synchronization phase.'
);

関連関数との比較

関数役割wordwrapとの違い
wordwrap()単語区切りを基準に文字列を折り返す本記事の対象。デフォルトでは単語の途中では改行しない
chunk_split()文字列を固定長ごとに機械的に分割する単語の区切りを考慮せず、指定文字数ごとに強制的に分割する
nl2br()改行文字をHTMLの<br>タグに変換する折り返し処理自体は行わず、既存の改行を変換するだけ
str_split()文字列を固定長の配列に分割する改行文字の挿入ではなく、配列として分割結果を得る
mb_strimwidth()指定した表示幅で文字列を切り詰める折り返しではなく「切り捨て」(省略記号付与)が目的

よくある落とし穴(注意点)

  1. マルチバイト文字(日本語など)には正しく対応していない wordwrap() はバイト単位で幅を計算し、かつ半角スペースを単語の区切りとして扱うため、スペースを含まない日本語の文章では期待通りに折り返されないことがあります。日本語テキストの折り返しには、mb_substr() を使った独自実装(例6を参照)や、mb_strwidth() を使った表示幅ベースの計算が必要です。
  2. $cut_long_words を指定し忘れて長い単語がはみ出す 長いURLやハッシュ値など、スペースを含まない長い文字列がテキスト中にあると、デフォルト設定ではその部分だけ指定幅を超えてしまいます。URLを含むテキストを扱う場合は $cut_long_wordstrue にすることを検討しましょう(例3を参照)。
  3. 改行文字の指定を環境に合わせていない Windows環境向けのテキストファイルを生成する場合など、改行コードとして "\r\n" が必要なケースもあります。用途に応じて第3引数を適切に指定しましょう。
  4. 既存の改行との相互作用を考慮していない 元のテキストに既に改行が含まれている場合、wordwrap() はそれを尊重しつつ追加の折り返しを行いますが、意図しない箇所で改行が増えることがあります。段落ごとに処理を分けるなどの工夫が有効です(例4を参照)。
  5. 幅の指定を「文字数」だと誤解する $width 引数は厳密には「バイト数」に近い基準で扱われます。ASCII文字のみのテキストであれば文字数と一致しますが、マルチバイト文字が混在する場合は注意が必要です。

まとめ

観点まとめ
何をする関数か指定した幅を超えないよう、単語の区切りを基準に文字列へ改行を挿入する
主な用途プレーンテキストメールの整形、CLIツールのヘルプ表示、固定幅レポートの生成など
マルチバイト対応非対応。日本語テキストにはmb_substr()などを使った独自実装が必要
長い単語への対応第4引数$cut_long_wordstrueにすることで強制的に分割できる
注意点マルチバイト非対応、改行コードの環境依存、幅指定がバイト数ベースであること

wordwrap() は、英語のようなスペース区切りの言語のテキストを固定幅で整形する際に非常に便利な関数です。ただし日本語のようなマルチバイト言語では素直には使えないため、対象言語の特性を理解した上で、必要に応じて mb_* 系関数と組み合わせる工夫を取り入れましょう。

タイトルとURLをコピーしました