2.1. Zeichenketten (Klasse string)

Lernziele

Die Klasse string
Anlegen, Kopieren, Abändern und Verketten von Strings
Zugriff auf Substrings

Am Anfang war das Wort und das Wort bei Gott und Gott war das Wort.“. Es ist schon eine biblische Weisheit, dass Worte etwas ungeheuer Wichtiges sind. Beginnen wir daher mit dem Datentyp von LEDA, der zum Speichern und Verarbeiten von Worten und Sätzen nützlich ist, dem Typ string, einem der einfachsten Datentypen von LEDA.

Ein String ist eine Zeichenkette, d. h. eine Folge von mehreren (oder auch gar keinem) Zeichen. Der LEDA-Typ string ist somit eng mit dem C++-Typ char[] verwandt, besitzt gegenüber diesem jedoch eine Reihe von Vorteilen, die wir gleich kennen lernen werden.

Wir wollen diesen Typ zunächst dazu benutzen, ein bisschen mit Worten zu spielen. Viele weitere Beispiele dieses Tutoriums sind Spiele mit Wörtern und Sätzen. Mit ihnen können komplexe Sachverhalte oftmals auf anschauliche und belustigende Weise dargestellt werden.

RETSINAKANISTER. Wie bitte? Der Autor ist von der Komplexität der Sprache C++ frustriert und möchte sich betrinken?[4] Nein, er hat ein Wort gebildet, das vorwärts wie rückwärts gelesen gleich ist! Ein solches Wort heißt Palindrom. Vernachlässigen wir dabei Leerzeichen, Satzzeichen und Groß-/Kleinschreibung, so können wir die Definition auf ganze Sätze ausdehnen. Einige berühmte Satzpalindrome sind „Ein Neger mit Gazette zagt im Regen nie“, „Nie grub Ramses Marburg ein“ oder der englische Satz „A man, a plan, a canal - Panama“.

Schreiben wir zunächst ein LEDA-Programm, das einen String von der Standardeingabe liest und testet, ob dieser ein Palindrom ist. Dazu erzeugt das Programm aus dem Eingabestring den umgedrehten String (d. h. den String mit umgekehrter Reihenfolge der einzelnen Zeichen) und vergleicht ihn mit dem ursprünglichen. Um den String umzudrehen, hängt es nacheinander alle Zeichen von hinten nach vorne an einen zweiten String an. Dieses Programm offenbart schon recht viele Eigenschaften von LEDA im Allgemeinen und LEDA-Strings im Besonderen.

Filename: PalindromTest.C
LEDA-Benutzer ab Version 5.0: Beachten Sie, dass die Header-Dateien nun in Module (Unterverzeichnisse) partitioniert sind!
#include <LEDA/string.h>
#include <iostream>

using leda::string;
using std::cout;

int main() {
  string s; // default initialization

  s.read_line();

  string r; 

  for(int i = s.length() - 1 ; i >= 0 ; i--) 
    r += s[i];   // inefficient, see below!

  if(s == r) // fast comparison of handle-like type
    cout << s << " is a palindrome\n";
  else
    cout << s << " is not a palindrome\n";
}

Hier wird zunächst der String s mit Default-Initialisierung definiert, d. h., bei der Definition wird die Variable auf den Default-Wert des Datentyps[5] gesetzt. Das ist typischerweise der „einfachste“ Wert des Typs; bei Strings ist das der Leerstring, d. h. der String, der aus keinem Zeichen besteht.

Strings bieten eine große Anzahl von Operationen an.[6] Über die Methode

s.read_line();

kann ein String s von der Standardeingabe gelesen werden. Dabei dient das Zeilentrennzeichen \n als Endmarkierung einer Zeile.

Das obige Programm hängt durch Verwenden des Operators += das jeweils nächste Zeichen des Strings s an den String r an. Allgemein kann durch

r += s;

ein String s an den String r angehängt werden. Der Operator += liefert dabei eine Referenz auf r zurück.

Auf die einzelnen Zeichen eines Strings wird dabei durch den Subskript-Operator [] zugegriffen:

char& c = s[i];

Er liefert eine Referenz auf das i-te Zeichen zurück, so dass über ihn dieses Zeichen auch abgeändert werden kann.

Der Vergleichsoperator

s == r;

vergleicht zwei Strings s und r miteinander.

Im Vergleich zum Typ char[] von C++ fällt auf, dass wir uns hier nicht um Allokation von Speicherplatz kümmern müssen. Der String r wird durch den Operator += auf magische Weise länger und länger.



[4] Ja, C++ ist manchmal frustrierend. Der Autor hat in diesem Tutorium versucht, nur Basiskonzepte dieser mächtigen Programmiersprache zu verwenden. Der Schwerpunkt liegt auf der Beschreibung der Typen und Algorithmen von LEDA, und daher bestehen die meisten Programme aus einem einzigen main().

[5] Falls es einen solchen gibt. Die eingebauten C++-Typen wie char, int oder double haben keinen Default-Wert und auch einige Typen von LEDA nicht.

[6] Wir müssen hier allerdings zugeben, dass LEDA-Strings nicht so mächtig sind wie die entsprechenden Datentypen auf Stringbehandlung spezialisierter Sprachen wie Perl und AWK. Einem Vergleich mit der gleichnamigen Klasse string aus der C++-Standardbibliothek halten sie aber stand; die beiden Klassen besitzen nahezu dieselbe Funktionalität.