Strings7 min readExamples run on PHP 8.5.10

strspn()

Learn how PHP 8.4 strspn() measures the initial run of allowed bytes in a string, including offset and length handling, edge cases and common mistakes.

Signature

strspn(string $string, string $characters, int $offset = 0, ?int $length = null): int

Purpose

strspn() counts how many bytes at the start of a string are all members of a set of allowed characters. It stops at the first byte that is not in the set and returns the count so far. It is a small, fast tool for tokenizing: skip a run of digits, measure a run of whitespace, or check that a value contains only permitted characters.

Signature

Parameters and defaults

  • $string: the text to examine.
  • $characters: the allowed characters, written as a plain list. Order and duplicates do not matter. The list is literal, so "a-z" means the three characters a, - and z, not a range.
  • $offset: where to start. The default is 0. A negative value counts from the end of the string.
  • $length: how many bytes to examine after the starting position. The default null means "to the end". A negative value stops that many bytes before the end of the string.

When you pass $offset or $length, the result behaves as if you had called strspn(substr($string, $offset, $length), $characters). The returned count is measured from the starting position, not from the beginning of the original string.

Return value and failure cases

The function always returns an int: the length of the initial matching segment. If the very first examined byte is not allowed, the result is 0. If every examined byte is allowed, the result equals the length of the examined part. The function does not return false for a non-matching string. Because $length is nullable since PHP 8.0, passing null explicitly is valid.

Example 1: basic runs

The first call counts the leading digits in a sentence. The second shows that a string which does not start with an allowed byte gives 0. The third shows that the set can contain several characters.

Example
<?php
echo strspn("42 is the answer", "1234567890"), "\n";
echo strspn("foo", "o"), "\n";
echo strspn("aabbcc", "ab"), "\n";
Output
2
0
4

Example 2: offset and length

Here each call examines a different slice. Remember that the count restarts at the offset.

Example
<?php
$s = "foo";
echo json_encode([
    strspn($s, "o", 1, 2),
    strspn($s, "o", 1, 1),
    strspn("abcdef", "abcdef", -3),
    strspn("abcdefxyz", "abcdef", 0, -3),
    strspn("abc123", "abc", 3)
]) . "\n";
Output
[2,1,3,6,0]

The -3 offset starts at def. The -3 length in the fourth call leaves out the last three bytes, so only abcdef is examined.

Example 3: validating a whole string

To test that every byte is allowed, compare the result with strlen(). Guard against the empty string if you do not want it to count as valid.

Example
<?php
function isHex(string $value): bool {
    return $value !== '' && strspn($value, '0123456789abcdefABCDEF') === strlen($value);
}

echo json_encode([isHex('ff00AA'), isHex('12xz'), isHex('')]) . "\n";
Output
[true,false,false]

Edge cases

  • Case sensitivity: strspn("ABC", "abc") is 0. Include both cases in the mask when you need both.
  • Bytes, not characters: the function is binary-safe and works on bytes. A multibyte UTF-8 character is several bytes, so list individual bytes only if you really intend that. For Unicode-aware checks, use preg_match() with the u modifier.
  • Empty input: an empty string gives 0. With an empty mask nothing is allowed, so the result is also 0.
  • Whole-string check: strspn($s, $mask) === strlen($s) is also true for an empty string, because both sides are 0.

Common mistakes

  1. Expecting ranges. "a-z" does not mean lowercase letters. Write out abcdefghijklmnopqrstuvwxyz or use ctype_lower() or a regular expression.
  2. Reading the result as an absolute position. With a non-zero offset, add the offset back if you need an index into the original string.
  3. Counting matches anywhere. The function only measures the leading run. In "ab12" with the set "12", the result is 0, not 2.
  4. Confusing it with strcspn(). strspn() measures bytes that are in the set, while strcspn() measures bytes that are not in it.
  5. Forgetting the empty string in validation helpers, as shown in the third example.
  • strcspn() finds the length of the initial segment that does not match the mask.
  • substr() explains how $offset and $length are interpreted.
  • strlen() is handy for whole-string comparisons.
  • ctype_digit() and preg_match() cover common validation tasks with different rules.
  • strpbrk() finds the first occurrence of any character from a list.

Recap

strspn() returns how many bytes at the start of a string, or of the slice chosen by $offset and $length, belong to a given set. It is case-sensitive, byte-based and literal about the mask. It always returns an integer, so a failed match is 0, never false.

Tested examples

Basic runs of allowed characters
<?php
echo strspn("42 is the answer", "1234567890"), "\n";
echo strspn("foo", "o"), "\n";
echo strspn("aabbcc", "ab"), "\n";
Output
2
0
4
Using offset and length
<?php
$s = "foo";
echo json_encode([
    strspn($s, "o", 1, 2),
    strspn($s, "o", 1, 1),
    strspn("abcdef", "abcdef", -3),
    strspn("abcdefxyz", "abcdef", 0, -3),
    strspn("abc123", "abc", 3)
]) . "\n";
Output
[2,1,3,6,0]
Validating a whole string
<?php
function isHex(string $value): bool {
    return $value !== '' && strspn($value, '0123456789abcdefABCDEF') === strlen($value);
}

echo json_encode([isHex('ff00AA'), isHex('12xz'), isHex('')]) . "\n";
Output
[true,false,false]