Funktion strcspn() - Anzahl nicht übereinstimmender Zeichen zu Beginn eines strings

In einer PHP-Anwendung müssen Zeichenketten häufig mit anderen Zeichenketten verglichen werden, damit man bestimmte Informationen über sie erhält. Eine Information die man evtl. benötigt, ist die Anzahl der Zeichen zu Beginn eines strings, bei der bestimmte Zeichen, die als Maske übergeben werden, nicht vorkommen. Die Zählung erfolgt solange, bis das erste Zeichen aus der Maske auftritt. Hierfür kann man in PHP die Funktion strcspn() verwenden. Sie funktioniert ähnlich wie strspn(), nur in umgekehrter Richtung. Innerhalb der runden Klammern werden die folgenden Parameter angegeben.

  1. Der string, der durchsucht werden soll (subject).
  2. Die Maske mit den Zeichen, die für die Zählung von Beginn an nicht enthalten sein sollen (mask).
  3. Die Startposition in der Zeichenkette, ab der die Zählung erfolgen soll (start, optional).
  4. Die Länge von dem Abschnitt des strings, der durchsucht werden soll (length, optional).

Der Rückgabewert der Funktion strcspn() ist eine Ganzzahl (Datentyp int). Beim Beispiel im folgenden Code ist der Rückgabewert die Zahl 3, da an der 4. Stelle des strings ein Zeichen vorkommt, das in der Maske enthalten ist (D). Die Reihenfolge der Zeichen in der Maske spielt dabei keine Rolle und der Vergleich erfolgt case-sensitive.

<?php

$str = 'ABCDEFGH';
$maske = 'HGFED';

// Ausgabe 3
echo strcspn($str, $maske);

?>

Die Startposition für die Zählung festlegen

Falls die Zählung nicht am Anfang des strings beginnen soll, kann man mit dem dritten Parameter eine Startposition festlegen. Beim folgenden Beispiel ist der Rückgabewert eine 2, da bei der Zählung das 1. Zeichen unberücksichtigt wird.

<?php

$str = 'ABCDEFGH';
$maske = 'HGFED';
$start = 1;

// Ausgabe 2
echo strcspn($str, $maske, $start);

?>

Maximale Länge des zu zählenden Teilabschnitts festlegen

Man kann auch die maximale Länge des Teilabschnitts festlegen, der beim Zählen berücksichtigt werden soll. Beim folgenden Beispiel wird das 1. Zeichen nicht berücksichtigt und der Teilabschnitt, der danach berücksichtigt wird, ist maximal 3 Zeichen lang, sodass die Ganzzahl 3 zurückgegeben wird, obwohl im string mehr Zeichen vorkommen, die nicht in der Maske enthalten sind.

<?php

$str = 'ABCDEFGH';
$maske = 'H';
$start = 1;
$length = 3;

// Ausgabe 3
echo strcspn($str, $maske, $start, $length);

?>

Nicht übereinstimmende Zeichen in Verbindung mit strlen() nutzen

Die Funktion strcspn() kann man in Verbindung mit strlen() oder mb_strlen() nutzen, um zu ermitteln, ob eine Zeichenkette bestimmte Zeichen enthält bzw. nicht enthält. Falls in der Zeichenkette die Zeichen vorkommen, die in der Maske festgelegt wurden, ist die Länge der beiden Funktionen unterschiedlich und das kann man z.B. für die Überprüfung auf nicht erlaubte Zeichen nutzen. Beim folgenden Beispiel wird in Verbindunbg mit der if-, else-Abfrage geprüft, ob der Dateiname ungültige Zeichen enthält.

<?php

$str1 = 'dateiname.txt';
$str2 = 'datei@name.txt';
$maske = '\'"\\?*:/@|<>';

// Ausgabe Dateiname ok
if (strlen($str1) != strcspn($str1, $maske))
{
  echo 'Dateiname nicht ok';
}
else
{
  echo 'Dateiname ok';
}

// Ausgabe Dateiname nicht ok
if (strlen($str2) != strcspn($str2, $maske))
{
  echo 'Dateiname nicht ok';
}
else
{
  echo 'Dateiname ok';
}

?>

Für solche Prüfungen werden in der Regel PCRE-Funktionen wie z.B. preg_match() verwendet. Diese sind jedoch sehr rechenintensiv, sodass die Ausführung länger dauert. Mit strlen() und strcspn() hat man einen Geschwindigkeitsvorteil.

Zählung bei Multibyte-Zeichen wie z.B. Umlauten in UTF-8

Technisch betrachtet zählt die Funktion nicht die Anzahl der nicht in der Maske enthaltenen Zeichen, sondern die Bytes. Hierbei wird davon ausgegangen, dass pro Zeichen 1 Byte belegt wird. Das kann bei Multibyte-Zeichen wie z.B. den Umlauten zu fehlerhaften Zählungen führen. Denn, ob ein Zeichen 1 Byte belegt oder mehr, hängt von der Zeichenkodierung ab. In UTF-8 belegen die Umlaute 2 Bytes, in ISO-8859-1 dagegen nur 1 Byte. Beim folgenden Beispiel ist der Rückgabewert 6, obwohl nur 3 Zeichen am Anfang des strings vorkommen, die in der Suchmaske nicht vorhanden sind.

<?php

$str = 'äöüABC';
$maske = 'ABC';

// Ausgabe 6
echo strcspn($str, $maske);

?>

Eigene Multibyte-Funktion zur Berücksichtigung der Zeichenkodierung

Laut dem Stand von 03/2016 gibt es für strcspn() keine interne Multibyte-Funktion, mit der auch die Umlaute oder andere Mehrbyte-Zeichen in UTF-8 korrekt gezählt werden. Man kann jedoch eine eigene Multibyte-Funktion erstellen und damit die Anzahl der Zeichen zählen lassen, bis ein Zeichen vorkommt, das in der Maske enthalten ist. Eine mögliche Lösung ist die Funktion mb_strcspn() im folgenden Code. Hierbei müssen die Zeichen der Maske in einem Array übergeben werden. Außerdem muss die Datei auch mit der angegebenen Zeichenkodierung gespeichert werden.

<?php

function mb_strcspn 
(
$str, 
$maske, 
$start = 0, 
$length = NULL, 
$encoding = 'UTF-8'
)
{
  $str = mb_substr ($str, $start, $length, $encoding);
  $count = 0;
  $checkstr = mb_substr($str, $count, 1, $encoding);

  while (in_array ($checkstr, $maske) == FALSE)
  {
    $count++;
    $checkstr = mb_substr($str, $count, 1, $encoding);
  }
  return $count;
}

$str = 'äöüABCDEF';
$maske = array ('A', 'B', 'C');
$start = 1;

echo mb_strcspn($str, $maske, $start);

?>

Zuerst werden die Parameter der Funktion mb_strcspn() festgelegt. Diese sind $str, $maske, $start, $length und $encoding. Die letzten drei Parameter werden mit Standardwerten vorbelegt, sodass diese gültig sind, falls hierfür beim Aufruf der Funktion keine Werte übergeben werden.

Für den Fall, dass $start und/oder $length angegeben wurden, wird mit mb_substr() der relevante Teil aus der Zeichenkette herausgelöst, der mit $start beginnt und die Länge von $length hat. Zusätzlich kann mit $encoding die Zeichenkodierung angegeben werden. Die Zählvariable $count wird auf 0 gesetzt, das erste Zeichen aus dem relevanten Teil der Zeichenkette wird für die Prüfung herausgelöst und in der Variable $checkstr gespeichert.

Danach wird überprüft, ob das Zeichen in der Variable $checkstr im Array $maske nicht enthalten ist. Ist das der Fall, wird die Zählvariable $count um 1 hochgezählt, das nächste Zeichen aus dem relevanten Teil wird herausgelöst und in der Variable $checkstr gespeichert. Danach kann die Prüfung von vorne beginnen. Für diesen Vorgang wird eine while-Schleife verwendet. Für die Überprüfung, ob das Zeichen nicht im Array $maske enthalten ist, wird die Funktion in_array() verwendet.

Die while-Schleife wird solange wiederholt, bis ein Zeichen an der Reihe ist, das im Array $maske enthalten ist. Ist das der Fall, wird die while-Schleife beendet und $count wird als Rückgabewert der Funktion übergeben.

Am Ende des Codes erfolgt ein Test mit der Ausgabe der Ganzzahl 2, da das erste Zeichen übersprungen wird und danach zwei Zeichen folgen, die nicht im Array $maske enthalten sind. Für $length und $encoding wurden keine Werte übergeben, sodass hierfür die Standardwerte gelten. Man könnte sie bei Bedarf jedoch angeben.