Php

How to Truncate a string in PHP to the word closest to a certain number of characters

25 September 2026 · 8 min read

How to Truncate a string in PHP to the word closest to a certain number of characters

In the dynamic world of web development, presenting information concisely yet completely is a perennial challenge. When dealing with user-generated content, database entries, or API responses, you often encounter strings far longer than intended for a given display area. While simply cutting a string at a fixed character count using basic functions like PHP’s substr() might seem straightforward, it frequently leads to awkward, cut-off words that diminish user experience. This article delves into how to truncate a string in PHP to the word closest to a certain number of characters, ensuring your text remains readable and professional, without breaking words mid-sentence. We’ll explore robust techniques that account for word boundaries and multi-byte characters, providing a sophisticated solution for common string manipulation needs.

The Challenge of Basic String Truncation in PHP

Many developers, when faced with the need to shorten text, instinctively turn to PHP’s built-in substr() function. This function is incredibly useful for extracting a portion of a string based on a start position and length. For instance, substr("Hello world", 0, 5) would return “Hello”. However, its simplicity becomes its biggest drawback when you’re dealing with display text.

Consider a scenario where you have a long paragraph, and you need to display only the first 100 characters in a preview. If the 100th character falls in the middle of a word, say “beautifully”, you might end up with “beautiful” or “beautifull”, followed by an abrupt cut. This not only looks unprofessional but can also make the text difficult to read and understand. Users expect a clean break, ideally at the end of a complete word, which substr() on its own cannot guarantee.

Furthermore, relying solely on character counts can be problematic for responsive designs where character limits might vary significantly across different screen sizes. A fixed character limit might work for a desktop view but truncate too aggressively or not enough for a mobile interface. A word-safe truncation method offers greater flexibility and a more consistent user experience, adapting to the natural flow of language rather than arbitrary character counts.

Crafting a Word-Safe Truncation Function

To overcome the limitations of simple character-based truncation, we need a method that respects word boundaries. The core idea is to find a suitable breaking point within the desired length, ensuring that we don’t cut off words. This often involves checking for the last space or punctuation mark before or at the target character limit.

A common approach involves using strrpos(), which finds the position of the last occurrence of a substring in a string. We can combine this with substr(). First, we take a substring up to our desired length. Then, we find the last space within that substring. If a space is found, we truncate at that space. If no space is found (meaning the first word itself is longer than the target length), we might decide to cut it anyway or adjust the logic based on specific requirements.

For example, if our target length is 50 characters, we first take the first 50 characters. Then, we look for the last space within those 50 characters. If the last space is at position 45, we would then truncate the original string at position 45. This ensures that the displayed text ends cleanly on a word, improving readability significantly. This method is fundamental to achieving a more intelligent PHP string truncation by word.

Handling Multi-Byte Characters with mb_substr

While substr() works perfectly fine for single-byte character encodings like ASCII, it falls short when dealing with multi-byte character sets such as UTF-8, which is prevalent on the web today. In UTF-8, a single character can occupy more than one byte of memory. If you use substr() on a UTF-8 string, it counts bytes, not characters, leading to corrupted characters or incorrect lengths when a multi-byte character is split.

This is where PHP’s Multi-Byte String (mbstring) extension becomes indispensable. Specifically, mb_substr() behaves identically to substr() but operates on characters rather than bytes. This is crucial for internationalized applications where text might contain characters from various languages (e.g., Chinese, Japanese, Korean, or extended Latin characters with accents).

To ensure your word-safe truncation function is robust and globally compatible, always use mb_substr() in conjunction with mb_strrpos() (or similar mb_ functions) and specify the character encoding (e.g., ‘UTF-8’). This guarantees that your string operations correctly interpret characters, preventing display issues and ensuring accurate truncation regardless of the language or character set used in your content. Ignoring multi-byte considerations can lead to broken text and a poor user experience for a significant portion of your audience.

Advanced Truncation: Adding Ellipsis and Customization

After successfully truncating a string to the nearest word, it’s common practice to append an ellipsis (...) to indicate that the text has been shortened. This provides a visual cue to the user that there’s more content available, encouraging them to click through to the full article or description. The ellipsis should only be added if the original string was indeed longer than the truncated version.

When you need to truncate a string in PHP to the word closest to a certain number of characters, the goal is often to find the “best” break point. This means not just cutting at the last space before the limit, but potentially adjusting the limit slightly to accommodate a full word. For example, if your target is 100 characters, and the last word ends at 98 characters, you’d prefer 98 characters plus ellipsis over cutting mid-word at 100.

The flexibility of a well-designed truncation function allows for customization. You might want to define the ellipsis character, specify if trailing whitespace should be trimmed, or even set a minimum word count before truncation occurs. These details allow the function to be adapted to various UI requirements, ensuring the truncated output always looks polished and intentional.

### Step-by-Step: Implementing Your PHP Word-Safe Truncation Function
  1. Define the Function Signature: Start by creating a function that accepts the string to be truncated, the maximum desired length, and optionally, an ellipsis string and encoding. Example: function truncate_word_safe($string, $length, $ellipsis = '...', $encoding = 'UTF-8').
  2. Handle Short Strings: Immediately check if the original string’s length (using mb_strlen()) is already less than or equal to the target $length. If so, return the original string as no truncation is needed.
  3. Perform Initial Truncation: Use mb_substr($string, 0, $length, $encoding) to get the initial segment of the string up to the desired character count. This gives us the potential maximum length.
  4. Find the Last Word Boundary: Use mb_strrpos() to find the position of the last space character within this initially truncated segment. For example, $last_space = mb_strrpos($truncated_string, ' ', 0, $encoding);.
  5. Adjust and Append Ellipsis:
    • If $last_space is found (meaning there’s a space within the segment): Re-truncate the original string up to $last_space using mb_substr($string, 0, $last_space, $encoding). Then, append the $ellipsis.
    • If $last_<b>Question & Answer : </b><br></br><p>I have a code snippet written in PHP that pulls a block of text from a database and sends it out to a widget on a webpage. The original block of text can be a lengthy article or a short sentence or two; but for this widget I can't display more than, say, 200 characters. I could use substr() to chop off the text at 200 chars, but the result would be cutting off in the middle of words-- what I really want is to chop the text at the end of the last <i>word</i> before 200 chars.</p><br></br><p>By using the <a href="http://www.php.net/wordwrap" rel="nofollow noreferrer">wordwrap</a> function. It splits the texts in multiple lines such that the maximum width is the one you specified, breaking at word boundaries. After splitting, you simply take the first line:</p> <pre>substr($string, 0, strpos(wordwrap($string, $your_desired_width), "\n")); </pre> <p>One thing this one-liner doesn't handle is the case when the text itself is shorter than the desired width. To handle this edge-case, one should do something like:</p> <pre>if (strlen($string) > $your_desired_width) { $string = wordwrap($string, $your_desired_width); $string = substr($string, 0, strpos($string, "\n")); } </pre> <hr></hr> <p>The above solution has the problem of prematurely cutting the text if it contains a newline before the actual cutpoint. Here's a version which solves this problem:</p> <pre>function tokenTruncate($string, $your_desired_width) { $parts = preg_split('/([\s\n\r]+)/', $string, null, PREG_SPLIT_DELIM_CAPTURE); $parts_count = count($parts); $length = 0; $last_part = 0; for (; $last_part < $parts_count; ++$last_part) { $length += strlen($parts[$last_part]); if ($length > $your_desired_width) { break; } } return implode(array_slice($parts, 0, $last_part)); } </pre> <p>Also, here is the PHPUnit test class used to test the implementation:</p> <pre>class TokenTruncateTest extends PHPUnit_Framework_TestCase { public function testBasic() { $this->assertEquals("1 3 5 7 9 ", tokenTruncate("1 3 5 7 9 11 14", 10)); } public function testEmptyString() { $this->assertEquals("", tokenTruncate("", 10)); } public function testShortString() { $this->assertEquals("1 3", tokenTruncate("1 3", 10)); } public function testStringTooLong() { $this->assertEquals("", tokenTruncate("toooooooooooolooooong", 10)); } public function testContainingNewline() { $this->assertEquals("1 3\n5 7 9 ", tokenTruncate("1 3\n5 7 9 11 14", 10)); } } </pre> <p>Special UTF8 characters like 'à' are not handled. Add 'u' at the end of the regex to handle it:</p> <p>$parts = preg_split('/([\s\n\r]+)/u', $string, null, PREG_SPLIT_DELIM_CAPTURE);</p>