Multibyte strings7 min readExamples run on PHP 8.5.10

mb_strimwidth()

Learn how mb_strimwidth() trims multibyte text by display width, how the trim marker counts toward the limit, and which mistakes to avoid.

Signature

mb_strimwidth(
    string $string,
    int $start,
    int $width,
    string $trim_marker = "",
    ?string $encoding = null
): string
Available since PHP 4.0.67.48.08.18.28.38.48.5All versions →

Purpose

mb_strimwidth() shortens a string so that it fits a given display width, not a given number of bytes or characters. Halfwidth characters such as ASCII letters count as 1 column. Fullwidth characters, common in Chinese, Japanese and Korean text, count as 2. This makes the function useful for fixed-width layouts such as table cells, console output and compact list titles, where a plain character count would give uneven results.

If you want an optional marker such as ... at the cut point, the function can add it and still keep the whole result within the requested width.

Signature

Parameters and defaults

  • $string: the text to trim.
  • $start: the character offset where the visible part begins. The first character is 0. A negative value counts from the end of the string.
  • $width: the maximum width of the result, including the trim marker. The manual notes that passing a negative width is deprecated as of PHP 8.3.0, so use a non-negative width.
  • $trim_marker: text added when the string is truncated. The default is an empty string, so no marker appears unless you supply one.
  • $encoding: the character encoding. If it is omitted or null, the internal encoding is used. Passing "UTF-8" explicitly keeps the code independent of configuration.

Return value and failure cases

The function returns a string. If the text from $start already fits within $width, it comes back whole. Otherwise the text is cut, and when a marker is given, the marker replaces the last columns so the total width matches the limit.

Since PHP 8.0.0, an invalid $encoding name throws a ValueError. Before 8.0 this produced a warning and false. In PHP 8.4 you can rely on getting a string back or an exception.

Example 1: the basic call

The marker counts toward the width. With a width of 10 and a three-character marker, seven characters of the original text remain.

Example
<?php
echo mb_strimwidth("Hello World", 0, 10, "..."), "\n";
Output
Hello W...

Example 2: fullwidth characters

Each character in the Japanese title below is 2 columns wide. With a width of 10 and a marker of 3 columns, only 7 columns remain for the text. That fits three fullwidth characters (6 columns), because a fourth would need 8. The result is 9 columns wide, not exactly 10.

Example
<?php
$title = "日本語のテキスト";
$short = mb_strimwidth($title, 0, 10, "...", "UTF-8");
echo json_encode(["text" => $short, "width" => mb_strwidth($short, "UTF-8")], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"text":"日本語...","width":9}

Example 3: start offsets and short strings

A string that already fits is returned unchanged and gets no marker. The $start offset is applied before the width is measured, and a negative offset counts from the end.

Example
<?php
$results = [
    "short" => mb_strimwidth("Short", 0, 10, "..."),
    "offset" => mb_strimwidth("Hello World", 6, 4, ".."),
    "negativeStart" => mb_strimwidth("Hello World", -5, 5, "..."),
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"short":"Short","offset":"Wo..","negativeStart":"World"}

In the offset case, the text from position 6 is World, which is 5 columns wide and does not fit in 4. Two columns go to the .. marker and two to Wo.

Edge cases

  • The result may be narrower than the width. A fullwidth character that would cross the limit is dropped entirely, so the result can end one column short, as in Example 2.
  • The marker takes space. A long marker leaves less room for real content. Keep the marker small compared with the width, and test the case where the width is barely larger than the marker.
  • The offset is applied first. The width limit is measured on the text after $start, not on the whole string.
  • Ambiguous characters. Width follows the East Asian width rules the manual points to. Some symbols may be narrower or wider than you expect, so check with mb_strwidth() when exact alignment matters.
  • Encoding. The text must be valid in the chosen encoding, and an unknown encoding name throws a ValueError.

Common mistakes

  1. Using substr() or strlen() for multibyte text. They count bytes and can cut a character in half. Use multibyte functions instead.
  2. Assuming the width is a character count. mb_strimwidth("日本語", 0, 4) measures columns, not characters, so it keeps only two characters.
  3. Adding the marker afterwards. Appending ... to an already trimmed string makes it wider than intended. Pass the marker as the fourth argument so it is included in the budget.
  4. Using negative widths. The behavior is deprecated as of PHP 8.3.0. Compute a start offset instead.
  5. Relying on the default encoding. If the internal encoding differs from your data, results will be wrong. Pass "UTF-8" explicitly when you know the data is UTF-8.
  • mb_strwidth() returns the display width of a string, which is the measure that mb_strimwidth() uses.
  • mb_internal_encoding() gets or sets the default encoding used when $encoding is null.
  • mb_substr() cuts by character count rather than display width.

Recap

mb_strimwidth() trims text by display columns, where fullwidth characters count as 2. The trim marker is counted inside the width, the offset is applied first, and a string that already fits is returned unchanged. Pass an explicit encoding and avoid negative widths.

Tested examples

Basic truncation with a trim marker
<?php
echo mb_strimwidth("Hello World", 0, 10, "..."), "\n";
Output
Hello W...
Fullwidth characters count as two columns
<?php
$title = "日本語のテキスト";
$short = mb_strimwidth($title, 0, 10, "...", "UTF-8");
echo json_encode(["text" => $short, "width" => mb_strwidth($short, "UTF-8")], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"text":"日本語...","width":9}
Start offsets and strings that already fit
<?php
$results = [
    "short" => mb_strimwidth("Short", 0, 10, "..."),
    "offset" => mb_strimwidth("Hello World", 6, 4, ".."),
    "negativeStart" => mb_strimwidth("Hello World", -5, 5, "..."),
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
Output
{"short":"Short","offset":"Wo..","negativeStart":"World"}