strcspn

Returns the length of the initial run of a string that contains none of the given characters.

Signature
strcspn(string $string, string $characters, int $offset = 0, ?int $length = null): int
  • Added in PHP 4.0

Parameters

ParameterTypeDescription
$stringstringThe string to examine.
$charactersstringA string listing every disallowed character.
$offsetoptionalint= 0Position in string to start scanning from. Negative values count from the end.
$lengthoptional?int= nullHow many characters of string to examine. Negative values stop that many characters from the end. null means to the end of the string.

Return value

intThe length of the initial segment of string that contains none of the characters in characters.

Changelog

  • PHP 8.4.0When characters is an empty string, the scan no longer stops incorrectly at the first null byte.
  • PHP 8.0.0The length parameter is nullable.

strcspn walks a string from the start and stops at the first character that appears in the $characters mask, returning how many characters it got through. Think of it as "length until any of these". Its mirror image, strspn, counts the run of characters that are in the mask.

When to reach for it

It shines when you want to find whichever of several delimiters comes first. Splitting key=value, key:value or key value with one call, trimming a line at the first # or ; comment marker, or grabbing the token before any whitespace or punctuation. Doing the same with strpos means one call per delimiter plus a min() over the results.

It is also a compact validator: if strcspn($s, $forbidden) === strlen($s), then none of the forbidden characters occur anywhere in $s.

What trips people up

The second argument is a set of characters, not a substring. strcspn($s, 'ab') stops at the first a or b, not at the sequence "ab".

When a forbidden character sits at the very start you get 0, which is a valid answer rather than a failure. And when $offset is set, the returned length is counted from that offset, not from the beginning of the string.

Example

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

When to use it

  • Split a config line at the first of several possible delimiters (=, : or space)
  • Cut a line at the first comment marker such as # or ;
  • Verify a filename contains no characters from a forbidden set

Frequently asked questions

What is the difference between strcspn and strspn?

strcspn counts the leading characters that are NOT in the mask, stopping at the first match; strspn counts the leading characters that ARE in the mask, stopping at the first non-match. The c stands for complement.

Does strcspn search for a substring?

No. The second argument is a set of individual characters, so strcspn($s, 'ab') stops at the first 'a' or the first 'b', whichever comes first. Use strpos to search for a literal substring.

Why does strcspn return 0?

Because the very first character examined is in the forbidden set. That is a normal result, not an error, so do not treat 0 as a failure value.

More examples

Splitting on the first of several delimiters

Each line prints host => local, port => 5432, debug => true. A single strcspn call handles all three delimiter styles, where strpos would need one call per delimiter plus a min().

Example · php
<?php
foreach (['host=local', 'port: 5432', 'debug true'] as $line) {
    $n   = strcspn($line, '=: ');
    $key = substr($line, 0, $n);
    $val = ltrim(substr($line, $n), '=: ');
    echo "$key => $val\n";
}

Validating a string against a forbidden set

report.pdf is valid because the scan reaches the end of the string; my:file.txt is invalid because the colon stops the scan at position 2, which is shorter than the string length.

Example · php
<?php
$bad = "/\\?%*:|\"<>";
foreach (['report.pdf', 'my:file.txt'] as $name) {
    $ok = strcspn($name, $bad) === strlen($name);
    echo $name, ': ', $ok ? 'valid' : 'invalid', "\n";
}

Using offset and length

The offset moves the starting point and the returned count restarts from there, which is the detail people misread. Limiting length caps the answer at the window size even if no forbidden character appears.

Example · php
<?php
$s = 'abc-def-ghi';
echo strcspn($s, '-'), "\n";        // 3
echo strcspn($s, '-', 4), "\n";     // 3 - counted from offset 4
echo strcspn($s, '-', 4, 2), "\n"; // 2 - only 'de' examined
echo strcspn($s, '-', -3), "\n";   // 3 - last three chars, no dash

Discussion

  • Be the first to comment on this lesson.