str_word_count

Counts the words in a string, or returns them as an array, optionally with their byte positions.

Signature
str_word_count(string $string, int $format = 0, ?string $characters = null): array|int
  • Added in PHP 4.3.0

Parameters

ParameterTypeDescription
$stringstringThe string to examine.
$formatoptionalint= 00 for the count, 1 for a list of words, 2 for position => word pairs.
$charactersoptional?string= nullExtra characters to treat as part of a word, such as digits or punctuation.

Return value

array|intAn int word count when format is 0, a list of words when format is 1, or an array mapping each word's byte position to the word when format is 2.

Changelog

  • PHP 8.0.0The characters parameter is nullable.

str_word_count scans a string for runs of alphabetic characters and either counts them, lists them, or reports where each one starts. Its idea of a word is narrow: letters only, plus an apostrophe or hyphen that appears inside a word but never at the start.

When to reach for it

Reading-time estimates, minimum-length validation on a description field, quick word-frequency tallies on English prose, and pulling a tag list out of a short label. Format 2 is the one people forget — it gives you byte offsets, which is what you need to highlight or link individual words back in the original string.

What trips people up

Digits are not word characters. str_word_count('PHP 8.5 rocks') returns 2, not 3, because 8.5 contains no letters. Pass the digits and the dot through the third argument if you want them counted.

It is also single-byte and locale-dependent. Accented letters, Cyrillic, Greek, CJK text and emoji are not recognised as letters, so a French or Russian sentence will be miscounted or return nothing. For any non-ASCII input use preg_split('/\s+/u', ...) or a preg_match_all with the \p{L} Unicode property instead.

Finally, format 2 keys are byte offsets — with a multi-byte string they will not line up with mb_substr() positions.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Estimate reading time for an article by dividing the word count by 200
  • Enforce a minimum word count on a product description or bio field
  • Extract a word list with byte offsets so each word can be wrapped in a highlight tag

Frequently asked questions

Why does str_word_count ignore numbers?

Its definition of a word is alphabetic characters only, with apostrophes and hyphens allowed inside a word. Pass the digits as the third argument, for example str_word_count($s, 0, '0123456789'), to have them counted.

Does str_word_count work with UTF-8 or accented text?

Not reliably. It is a single-byte, locale-dependent function, so accented letters and non-Latin scripts are not treated as word characters. Use preg_split('/\s+/u', trim($text)) or preg_match_all('/\p{L}+/u', ...) instead.

What is the difference between format 1 and format 2?

Format 1 returns a plain list of the words found; format 2 returns the same words keyed by their starting byte offset in the input string, which lets you locate each word in the original text.

More examples

Counting digits and versions as words

Without the third argument only PHP, ships and in count. Adding digits and the dot makes "8.5" and "2025" count too, and the printed list shows all five tokens.

Example · php
<?php
$s = 'PHP 8.5 ships in 2025';
echo str_word_count($s), "\n";                    // 3
echo str_word_count($s, 0, '0123456789.'), "\n";  // 5
print_r(str_word_count($s, 1, '0123456789.'));

Reading-time estimate

640 words at 200 words per minute rounds up to a 4 minute read. max(1, ...) keeps very short posts from displaying "0 min read".

Example · php
<?php
$article = str_repeat('word ', 640);
$words   = str_word_count($article);
$minutes = max(1, (int) ceil($words / 200));
echo "$words words\n";      // 640 words
echo "$minutes min read\n"; // 4 min read

Highlighting words using their positions

Format 2 reports offsets 0, 4 and 10. The final substr confirms the offset is a real byte position in the original string, which is what you need for wrapping words in markup.

Example · php
<?php
$text = 'red green blue';
foreach (str_word_count($text, 2) as $pos => $word) {
    echo str_pad((string) $pos, 3, ' ', STR_PAD_LEFT), ": $word\n";
}
var_dump(substr($text, 10, 4)); // string(4) "blue"

Discussion

  • Be the first to comment on this lesson.