String in Array aufspalten – Programmieren lernen mit JavaScript – Thytos
Nächstes Video startet in 3 Sekunden.
Programmieren lernen mit JavaScript

String in Array aufspalten

Um ein String in ein Array zu spal­ten, muss ein Mus­ter im String er­kannt wer­den, an dem der String auf­ge­trennt wird.

Ein Array zu einem String zusammenzufassen, geht relativ einfach.

function join(array, delimiter) {
  for (var i = 0, res = ""; i < array.length; i++) {
    res += array[i];
    if (i < array.length - 1) {
      res += delimiter;
    }
  }
  return res;
}

join(["abc", "de", "fghi", "jklmn"], "|");
// => "abc|de|fghi|jklmn"

Andersrum ist es schwieriger: Wie kann erreicht werden, ein String wie "abc|de|fghi|jklmn" wieder in ein Array aufzuspalten?
In diesem Artikel soll die Funktion split geschrieben werden, Englisch für spalten / trennen / teilen, die das Gegenteil der join-Funktion darstellt.

Es ist gut, sich eine Variable mit einem String zu schreiben, mit dem während des Entwicklungsprozesses getestet werden soll.

var testString = "abc|de|fghi|jklmn";

Der senkrechte Strich ist in diesem Fall die Trennung, an der der String ausgespalten werden soll.

Die split-Funktion soll den zu spaltenden String annehmen, zusammen mit dem Trennzeichen. Zurückgegeben werden soll ein Array, in dem die Teilstrings aufgelistet sind.

function split(str, delimiter) {
  var res = []; // Diesem Array werden die Teilstrings hinzugefügt

  /* Die eigentliche Trenn-Action wird hier implementiert */

  return res; // Das Array wird zurückgegeben
}

Um den String an den Trennzeichen zu teilen, müssen diese Trennzeichen im String überhaupt erst gefunden werden. Dazu wird der String Zeichen für Zeichen abgesucht und geprüft, ob das jeweilige Zeichen dem Trennzeichen entspricht.
Ihr hört es sicherlich schon heraus: Hier wird Code wiederholt ausgeführt – das ruft nach einer Schleife.

for (var i = 0; i < str.length; i++) {
  if (str[i] === delimiter) {
    // Ein Trennzeichen wurde im String gefunden
    // Aber was jetzt?
  }
}
…

Verschachtelung von Schleifen

Wenn ein Trennzeichen im String gefunden wurde, soll ein Teilstring bis zu dieser Stelle extrahiert und dem Ergebnis-Array hinzugefügt werden. Wie wird ein Teilstring extrahiert?
Auch hier kann eine Schleife eingesetzt werden. Einer Variablen tmpStr, temporärer String, wird Zeichen für Zeichen aus dem originalen String hinzugefügt, bis zu der Stelle, an der das Trennzeichen steht.
Dadurch befindet sich eine Schleife nun innerhalb einer anderen Schleife. Deswegen ist Achtung geboten: Die Laufvariable muss unterschiedlich benannt sein. Ansonsten zählen beide Schleifen dieselbe Laufvariable hoch, wodurch es zu einem fehlerhaften Ergebnis kommt. Statt i wird die Laufvariable der inneren Schleife j genannt.

var tmpStr = "";
for (var j = 0; j < i; j++) {
  tmpStr += str[j];
}
res[res.length] = tmpStr;
…

Insgesamt sieht die Funktion dadurch folgendermaßen aus:

function split(str, delimiter) {
  for (var i = 0, res = []; i < str.length; i++) {
    if (str[i] === delimiter) {
      for (var j = 0, tmpStr = ""; j < i; j++) {
        tmpStr += str[j];
      }
      res[res.length] = tmpStr;
    }
  }
  return res;
}

Das Ergebnis geht schon in die richtige Richtung, wenn es mit dem testString ausprobiert wird. Ein Problem gibt es allerdings.

split(testString, "|");
// => ["abc", "abc|de", "abc|de|fghi"]

Die Teilstrings beginnen alle am Beginn des ursprünglichen Strings. Stattdessen sollten sie an der Stelle des zuletzt gefundenen Trennzeichens beginnen.
Dazu muss die Stelle des zuletzt gefundenen Trennzeichens gespeichert werden. Die innere Schleife beginnt dann beim zuletzt gefundenen Trennzeichen + 1 zu zählen. Aufgrund des + 1 wird der initiale Wert von lastDelimiter auf -1 gesetzt.

function split(str, delimiter) {
  for (var i = 0, res = [], lastDelimiter = -1; i < str.length; i++) {
    if (str[i] === delimiter) {
      for (var j = lastDelimiter + 1, tmpStr = ""; j < i; j++) {
        tmpStr += str[j];
      }
      res[res.length] = tmpStr;
      lastDelimiter = i;
    }
  }
  return res;
}

split(testString, "|");
// => ["abc", "de", "fghi"]

Funktionalität auslagern

Die Funktion sieht schon ganz gut aus, allerdings leider auch etwas komplex und unübersichtlich. Um den Code lesbarer zu machen, wird die Funktionalität der inneren Schleife in eine eigene Funktion ausgelagert und substring genannt, Teil-String.

function substring(str, start, end) {
  for (var j = start, tmpStr = ""; j < end; j++) {
    tmpStr += str[j];
  }
  return tmpStr;
}

function split(str, delimiter) {
  for (var i = 0, res = [], lastDelimiter = -1; i < str.length; i++) {
    if (str[i] === delimiter) {
      res[res.length] = substring(str, lastDelimiter + 1, i);
      lastDelimiter = i;
    }
  }
  return res;
}

split(testString, "|");
// => ["abc", "de", "fghi"]

Mit der Auslagerung von substring ist die split-Funktion schon etwas kürzer und einfacher zu verstehen.

Das Ergebnis ist noch nicht ganz richtig: Der Rückgabewert enthält drei Listen-Elemente, im String sind jedoch vier:

"abc|de|fghi|jklmn" // 4 Teilbereiche

["abc", "de", "fghi"] // Nur 3 Einträge

Der letzte Teil wird nicht dem Array hinzugefügt, weil kein Trennstrich am Schluss gefunden wird.
Zur Lösung kann die neue substring-Funktion genutzt werden: Nach der Schleife wird einfach der Teilstring vom zuletzt gefundenen Trennzeichen bis zum Ende des Strings dem Array hinzugefügt.

function split(str, delimiter) {
  for (var i = 0, res = [], lastDelimiter = -1; i < str.length; i++) {
    if (str[i] === delimiter) {
      res[res.length] = substring(str, lastDelimiter + 1, i);
      lastDelimiter = i;
    }
  }
  // Füge den Rest bis zum Ende des Strings hinzu
  res[res.length] = substring(str, lastDelimiter + 1, str.length);
  return res;
}

split(testString, "|");
// => ["abc", "de", "fghi", "jklmn"]

Durch die Auslagerung in eine eigene Funktion wurde die Funktionalität gekapselt und wiederverwendbar gemacht. Das Hinzufügen des letzten Eintrages war dadurch sehr einfach möglich.

Mehrzeichige Trennungen

Die join-Funktion kann nicht nur mit einem Trennzeichen, sondern auch mit einem mehrzeichigen Trennstring aufgerufen werden.

join(["abc", "de", "fghi", "jklmn"], " $$ ")
// => "abc $$ de $$ fghi $$ jklmn"

Wenn die split-Funktion das Gegenteil der join-Funktion darstellen soll, muss diese auch mit längeren Trennmustern umgehen können. Aktuell ist das leider nicht der Fall.

split("abc $$ de $$ fghi $$ jklmn", " $$ ")
// => ["abc $$ de $$ fghi $$ jklmn"]

Wie muss die split-Funktion geändert werden, damit sie auch Trennmuster verarbeiten kann, die mehrere Zeichen lang sind?

Auch hier kommt die substring-Funktion zugute. Die Stelle, an der die Trennung im String erkannt wird, befindet sich in der if-Bedingung.

if (str[i] === delimiter) { …

Dort wird ein einzelnes Zeichen mit dem Trennmuster verglichen. Stattdessen sollte hier ein Teilstring in der Länge des Trennmusters verglichen werden.

if (substring(str, i, i + delimiter.length) === delimiter) { …

Am besten ist es, die Länge des Delimiters in einer eigenen Variable festzuhalten, denn sie wird an mehreren Stellen gebraucht.

function split(str, delimiter) {
  // Variablendefinition aus dem Schleifenkopf
  // ausgelagert, um ihn übersichtlicher zu machen
  var res = [];
  var delLen = delimiter.length;
  var lastDel = -delLen; // Name verkürzt. Vorher lastDelimiter
  for (var i = 0; i < str.length; i++) {
    if (substring(str, i, i + delLen) === delimiter) {
      res[res.length] = substring(str, lastDel + delLen, i);
      lastDel = i;
    }
  }
  res[res.length] = substring(str, lastDel + delLen, str.length);
  return res;
}

split("abc $$ de $$ fghi $$ jklmn", " $$ ");
// => ["abc", "de", "fghi", "jklmn"]

Durch diese Änderungen ist es möglich, auch längere Trennmuster zum Spalten von Strings zu verwenden. Falls ihr nicht sofort versteht, wie das funktioniert, studiert den oberen Code und spielt damit in eurer Browser-Konsole herum.

Durch eine kleine Erweiterung kann der Code optimiert werden: Wenn ein Trennmuster gefunden wurde, kann direkt hinter das Ende des Trennmusters gesprungen werden, um die nächste Trennung zu suchen.

    …
    lastDel = i;
    i += delLen - 1; // i hochsetzen
  }
…

Die Laufvariable wird durch i += delLen-1; hochgesetzt. Anschließend folgt die finale Anweisung des Schleifenkopfs, i++, sodass i insgesamt um die Länge des Delimiters erhöht wurde und dadurch im nächsten Schleifendurchlauf an der Stelle hinter dem Trennmuster im String ist.

Native Funktionen

Die join-Funktion, split und substring sind alles nützliche Funktionen – und deswegen gibt es sie auch schon längst in JavaScript.

Um ein Array zu einem String zusammenzufügen, wird dahinter .join() geschrieben und ein Delimiter übergeben.

["abc", "de", "fghi", "jklmn"].join("|");
// => "abc|de|fghi|jklmn"

Um einen String entgegengesetzt wieder in ein Array aufzuspalten, wird .split() geschrieben und das Trennmuster übergeben.

"abc|de|fghi|jklmn".split("|");
// => ["abc", "de", "fghi", "jklmn"]

// Auch mit längeren Trennmustern möglich

"abc $$ de $$ fghi $$ jklmn".split(" $$ ");
// => ["abc", "de", "fghi", "jklmn"]

Auch die substring-Methode existiert.

"abcdefghij".substring(3, 8);
// => "defgh"

Wozu sollten also die Methoden hier neu implementiert werden?
Die Aufgaben sollten zeigen, dass ihr mit den Werkzeugen, die ihr bisher an die Hand bekommen habt, schon jetzt Funktionen umsetzen könnt, die in JavaScript nativ implementiert sind. Es soll euch ein tieferes Verständnis geben, was hinter den Methoden steckt, wenn ihr sie aufruft.
Außerdem konntet ihr sehen: Während der Entwicklung tauchen immer wieder Fehler auf. Das ist völlig normal und Teil des Entwicklungsprozesses. Kein Programmcode ist sofort perfekt. Wichtig ist es, die Fehler zu erkennen und damit umzugehen.

Es gibt allerdings einen Unterschied in der Schreibweise zwischen den Funktionen, die hier umgesetzt wurden, und denen, die JavaScript nativ mitbringt.

// Den eigenen Funktionen wird das Array / der String übergeben
push(array, "etwas");
join(array, ", ");
split(string, ", ");
substring(string, 3, 8);

// Die nativen Methoden werden hinter dem Array / String aufgerufen
array.push("etwas"); // array wird auch nicht als Parameter übergeben
array.join(", ");
string.split(", ");
string.substring(3, 8);

Die nativen Methoden werden mit einem Punkt getrennt hinter dem Array aufgerufen und benötigen auch nicht das Array als Parameter.
Das kennt ihr bereits vom length-Attribut.

array.length
string.length

Das liegt daran, weil Arrays Objekte sind. Objekte bringen ihre eigenen Eigenschaften und Funktionen mit. Funktionen, die an Objekten hängen, heißen Methoden.