Strings

<-- zurck zur Startseite | <- eine Seite vor | eine Seite weiter ->

  1. Anlegen von Strings
  2. Verketten von Strings
  3. String-Länge abfragen
  4. Methoden zum Vergleichen
  5. Suchen von Teilstrings
  6. Extrahieren von Teilstrings
  7. Ersetzen von Zeichen
  8. Umwandlung von primitiven Datentypen in Strings
  9. Übung
  10. Lösung

1. Anlegen von Strings

Strings sind Zeichenketten und in Java, ebenso wie Arrays, Objekte. Das liegt daran, das String intern als Array aus "char" (character, also Zeichen) bearbeitet wird. Das bedeutet auch, das Strings, wie Arrays, in ihrer Größe unveränderlich sind. Beim Verlängern etc. muss daher jedes Mal ein neuer String angelegt werden und der Alte gelöscht. Welche Konsequenzen sich daraus ergeben, werden wir gleich noch besprechen.
Die Klasse String liegt im Paket java.lang. Dieses Paket ist allerdings so wesentlich, dass es vom Compiler automatisch inkludiert wird und somit nicht manuell importiert werden muss, wie das z.B. beim Paket "java.util" der Fall ist.

Zunächst einmal sehen wir uns an, wie man einen String anlegt. Vor dem Variablennamen wird wie immer der Daten- bzw. Objekttyp angeführt, in diesem Falle String. Die wohl einfachste Möglichkeit, einen String zu erzeugen, ist es, der String-Variablen ein Literal zuzuweisen:

String text = "Hier kommt ein Text";

Da es sich aber, wie gesagt, bei Strings um Objekte handelt, kann ein String auch über den Konstruktor der Klasse "String" angelegt werden, wie bei Arrays mit dem Schlüsselwort new. Das Ergebnis ist dasselbe. Ein Beispiel:

String text = new String("Hier kommt ein Text");

Unbedingt zu beachten ist, dass die reine Deklaration eines Strings ohne Zuweisung nicht dasselbe ist wie ein Leerstring:

String text1;
String text2 = "";
String text3 = new String();

Während die String-Variable "text1" noch komplett leer ist, beinhaltet die Variable "text2" bereits einen String, auch wenn er noch der Länge 0 ist. Ein Leerstring ist in der Informatik nicht gleichzusetzen mit "nichts"! Würde man nämlich an den String "text1" einen weiteren Text anhängen wollen, so würde beim Ausführen des Programms an dieser Stelle ein Fehler erzeugt werden (auch wenn der Compiler zunächst nicht meckert). Um an einen String etwas anhängen zu können, bzw. sonstige Operationen durchführen zu können, muss er erst einmal existieren, und wenn es nur ein Leerstring ist. Der String "text2" würde sich dagegen ohne Probleme mit anderen Strings verketten lassen. Der dritte Aufruf - ohne Übergabe an den Kosntruktor - würde ebenfalls einen Leerstring erzeugen.

nach oben

2. Verketten von Strings

Bleiben wir gleich beim Verketten von Strings. Eine Möglichkeit haben wir bereits kennengelernt: mit dem +-Operator. Wir haben diesen Operator bisher verwendet, wenn wir einzelne Textteile bei der Bildschirmausgabe verknüpfen wollten. Die zweite Möglichkeit bietet die Methode concat der Klasse "String":

public String concat(String str)

Diese Methode erhält als Argument den String, der an den aktuellen String angefügt werden soll, und gibt einen neuen String zurück. Einigen wird auffallen, dass, im Gegensatz zu bisherigen Methoden, das Schlüsselwort "static" fehlt. Das bedeutet, dass diese Methode keine Klassenmethode ist und über den Klassennamen aufgerufen werden kann, wie wir das bis jetzt bei den Klassen "Math" und "Arrays" gesehen haben. Sie kann nur über ein String-Objekt aufgerufen werden, also ein Objekt, das auf der Klasse "String" erzeugt wurde. Sehen wir uns ein Beispiel an:

String text = "Hallo";
text = text + ", willst du mir ";
text = text.concat("ein paar Tips geben?");

In diesem Beispiel wird sukzessive ein ganzer Satz aufgebaut. Zunächst wird das in der Variable "text" gespeicherte Wort "Hallo" über den +-Operator zu einem Teilsatz erweitert. Für die nächste Verknüpfung wurde exemplarisch die Methode "concat" verwendet. Diese Methode wird auf der Variable "text" aufgerufen, das ja ein String-Objekt ist. Die Trennung zwischen Objekt und Methode erfolgt durch einen Punkt. Der der Methode übergebene String wird so dem String-Objekt "text" angefügt. Rückgabewert ist ein neuer String, den wir aber wieder in der Variable "text" speichern.

nach oben

3. String-Länge abfragen

Während bei Arrays deren Länge in der Eigenschaft length gespeichert wird, gibt es für Strings eine Methode mit gleichem Namen:

public int length()

Rückgabewert dieser Funktion ist eine Integer-Zahl, die die Länge des Strings (also die Anzahl der Zeichen, inkl. Leerzeichen), zurückgibt. Auch diese Methode benötigt - wie alle anderen Methoden der Klasse "String" - ein String-Objekt, um aufgerufen werden zu können:

String text = "Dies soll nur ein kurzer Satz sein!";
System.out.println("Der Satz besitzt genau " + text.length() + " Zeichen");

nach oben

4. Methoden zum Vergleichen

Des Weiteren bietet die Klasse "String" auch einige Methoden, mit denen man Strings vergleichen kann:

public boolean equals(Object anObject)
public boolean equalsIgnoreCase(String anotherString)
public boolean startsWith(String prefix)
public boolean endsWith(String suffix)
public int compareTo(String anotherString)
public int compareToIgnoreCase(String anotherString)
public boolean regionMatches(int toffset, String other, int ooffset, int len)
public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)

Die Methode equals vergleicht das String-Objekt, zu dem es aufgerufen wurde, mit dem übergebenen String. Stimmen beide überein, ist der Rückgabewert "true", ansonsten "false". Da allerdings Groß- und Kleinschreibung berücksichtigt werden, wäre "Text" nicht dasselbe wie "text". Will man Groß- und Kleinschreibung beim Vergleich ingorieren, verwendet man die Methode equalsIgnoreCase.
Achtung: Zwei Strings sollten nie mit dem Vergleichsoperator == verglichen werden. Er überprüft hier nämlich nicht die Gleichheit der Zeichenkette, sondern ob es sich um das gleiche Objekt handelt. Also bei Vergleichen mit Strings immer equals verwenden!
Die Methoden startsWith und endsWith überprüfen, ob der String mit der als Argument übergebenen Zeichenkette beginnt bzw. endet. Ist dies der Fall, geben beide Methoden "true" zurück, ansonten "false".
Die Methode compareTo führt einen sog. lexikalischen Vergleich zwischen dem String, zu dem die Methode aufgerufen wurde, und dem übergebenen String durch. Auffällig ist, dass der Rückgabewert kein boolescher Wahrheitswert, sondern eine Ganzzahl. Bei einem Rückgabewert von 0 sind beide Zeichenketten gleich. Bei einem negativen Rückgabewert ist das aktuelle String-Objekt kleiner als die der Methode übergebene Zeichenkette, bei einem positiven Rückgabewert größer. Die Besonderheit liegt darin, dass die Größe des Rückgabewertes etwas über den Grad der Verschiedenheit beider Strings aussagt: je größer der Betrag des Rückgabewertes, desto stärker unterscheiden sich die beiden Strings, wobei sich der Wert aus der Differenz der Unicode-Zahlen der einzelnen im String enthaltenen Zeichen zusammensetzt. Die Variante compareToIgnoreCase führt wieder einen Vergleich unter Mißachtung von Groß- und Kleinschreibung durch.
regionMatches dient dazu, Teilbereiche zweier Strings zu vergleichen. Das erste Argument stellt dabei die Startposition des aktuellen Strings dar, als zweites Argument wird der zu vergleichende String übergeben, dessen Teilbereich an der als drittes Argument übergebenen Stelle beginnt. Zuletzt wird der Methode schließlich die Länge der zu vergleichenden Teilbereiche übergeben. Da diese Methode ebenfalls Groß- und Kleinschreibung unterscheidet, gibt es eine Variante, die dies missachtet. Dabei wird als erstes Argument ein boolescher Wert übergeben, und zwar "true", wenn Groß- und Kleinschreibung ignoriert werden sollen. Die anderen Argumente rutschen einfach nach hinten.
Zu beachten ist, dass die Indexposition der einzelnen Zeichen innerhalb des Strings - wie bei Arrays - bei 0 beginnt und bei length()-1 endet!
Und wie immer ein kleiner Beispielquelltext zu diesen Methoden:

String text1 = "Hallo du, wie laeuft es?";
String text2 = "Hallo Du, wie laeuft es?";
String text3 = "Wieso bleibst du nicht?";
System.out.println(text1.equals(text2));
System.out.println(text1.equalsIgnoreCase(text2));
System.out.println(text3.startsWith("Wieso"));
System.out.println(text2.endsWith("nicht?"));
System.out.println(text2.compareTo(text1));
System.out.println(text2.compareToIgnoreCase(text1));
System.out.println(text3.regionMatches(0, text1, 10, 3));
System.out.println(text3.regionMatches(true, 0, text1, 10, 3));

Die Ergebnisse sollten für sich sprechen und auch so leicht ersichtlich sein.
Beim Aufruf von "compareTo" werden "text2" und "text1" miteinander verglichen. Sie unterscheiden sich nur in der Großschreibung des Wortes "du", weswegen das Ergebnis -32 ist, da sich Groß- und Kleinbuchstaben in der Unicode-Darstellung immer um genau 32 unterscheiden. "compareToIgnoreCase" hingegen liefert 0 zurück, da sich bei Missachtung von Groß- und Kleinschreibung beide String völlig gleichen. Noch Anmerkung zu "regionMatches": Hier wird das "Wie" aus "text3" mit dem "wie" aus "text1" verglichen. Die Länge des Teilstrings ist 3 (viertes Argument), der Teilstring beginnt bei "text3" an der Indexposition 0, bei "text1" an der Position 10. Ergebnis ist FALSE, wird jedoch - wie beim zweiten "regionMatches"-Aufruf - die Unterscheidung von Groß- und Kleinschreibung deaktiviert, ergibt der Vergleich TRUE.

nach oben

5. Suchen von Teilstrings

Sehen wir uns nun ein paar Methoden zum Suchen von Zeichen oder Zeichenketten innerhalb eines Strings an:

public int indexOf(String str)
public int indexOf(String str, int fromIndex)
public int lastIndexOf(String str)

Die Methode indexOf sucht das erste Vorkommen des übergebenen Zeichens bzw. der übergebenen Zeichenkette im aktuellen String und liefert den Index als Ganzzahl zurück. Die zweite Variante erhält als zweites Argument eine Startposition, an der die Suche begonnen werden soll.
Dem gegenüber sucht die Methode lastIndexOf das erste Vorkommen von hinten, wobei auch hier der Index zurückgegeben wird.
Für beide Methoden gilt: ist die Suche ergebnislos, wird -1 zurückgegeben. Ausserdem akzeptieren sie als erstes Argument an Stelle eines Strings auch ein "char".
Ein kleines Beispiel:

String myText = "No denn, wolle mer mal guggen...";
int pos1 = myText.indexOf("e");
int pos2 = myText.indexOf("e", 5);
int pos3 = myText.lastIndexOf("mal");
System.out.println("Das e wurde zuerst an der Position " + pos1 + " gefunden");
System.out.println("Bei der Suche ab Index 5 allerdings erst bei Position " + pos2);
System.out.println("Die Zeichenkette \"mal\" wurde von hinten zuerst an der Position " + pos3 + " gefunden");

nach oben

6. Extrahieren von Teilstrings

An Methoden zum Extrahieren von Zeichen aus dem aktuellen String stellt Java folgende Methoden aus der Klasse "String" zur Verfügung:

public String trim()
public char charAt(int index)
public String substring(int beginIndex)
public String substring(int beginIndex, int endIndex)

Die Methode trim entfernt alle Leerzeichen am Anfang und am Ende des Strings.
Die Methode charAt gibt - wie der Name schon sagt - das Zeichen an dem als Argument übergeben Index als "char" zurück. Der Index reicht - wie gewohnt - von 0 bis length()-1. Werden die Grenzen des Strings überschritten, wird eine Ausnahme ausgelöst (genauer:StringIndexOutOfBoundsException. Solange wir uns also noch nicht mit der Fehlerbehandlung beschäftigt haben, heißt es also aufpassen!
Von der Methode substring existieren zwei Varianten: die erste erwartet nur ein Argument. Diese Methode schneidet aus dem aktuellen String einen Teilstring aus, der von der übergeben Position bis zum Ende des aktuellen Strings reicht. Dieser Teilstring wird dann zurückgegeben. Die zweite Variante erlaubt als zweites Argument die Endposition des zu extrahierenden Teilstrings. Doch Vorsicht: im Gegensatz zu gleichartigen Funktionen in anderen Programmiersprachen, stellt das zweite Argument nicht die Länge des Teilstrings dar, sondern die Endposition, und zwar diejenige, die gerade nicht mehr zum extrahierten Teilstring gehört!
Ein Beispiel zur Veranschaulichung:

String myText = "   Dieser String dient zur Demonstration der Methoden der Zeichenextraktion           ";
myText = myText.trim();
char zeichen = myText.charAt(5);
String wort = myText.substring(0, 6);
System.out.println("Zeichen an der Position 5: " + zeichen);
System.out.println("Ergebnis der Methode substring: " + wort);

Zunächst werden die Leerzeichen am Anfang und Ende des Strings entfernt, da sie eigentlich überflüssig sind. Dies kann z.B. bei Benutzereingaben oft der Fall sein. Anschließend wird das Zeichen mit dem Index 5 ermittelt. Dieses das r aus dem Wort "Dieser" (die Leerzeichen sind jetzt schon weg und werden deshalb nicht mehr gezählt). Der Aufruf von "substring" liefert das komplette Wort "Dieser" zurück: als zweites Argument wird die Position des ersten Zeichens angegeben, das nicht mehr dazugehören soll. Das r gehört noch zum Wort, das wir haben wollen, und hat den Index 5. Ergo muss das zweite Argument folglich 5+1, also 6 sein!

nach oben

7. Ersetzen von Zeichen

Zum Ersetzen von Zeichenketten stehen ebenfalls 3 Methoden zur Verfügung:

public String toLowerCase()
public String toUpperCase()
public String replace(char oldChar, char newChar)

Diese Methoden sind eigentlich recht leicht zu verstehen. Während toLowerCase den String, zu dem es aufgerufen wird, komplett in Kleinbuchstaben umwandelt, macht toUpperCase genau das Gegenteil: Rückgabewert ist ein String, der zwar dem ursprünglichen String vom Text her entspricht, nun aber komplett in Großbuchstaben geschrieben ist.
Die Methode replace ersetzt im aktuellen String alle Zeichen, die als erstes Argument übergeben werden, mit dem Zeichen als zweites Argument. An der Methodendefinition sieht man schnell, dass diese Methoden nur Einzelzeichen ersetzt!

String myText = "Noch ein String zum Txsten...";
myText = myText.replace('x', 'e');
System.out.println("In Kleinbuchstaben: " + myText.toLowerCase());
System.out.println("In Grossbuchstaben: " + myText.toUpperCase());

Zuerst wird der Schreibfehler ausgebessert und das ä durch ein e ersetzt. Achtung: die Methode erlaubt als Übergabeparameter nur "char", deswegen müssen die Zeichen in einfache Hochkommata gestellt werden! Bei doppelten Hochkommata nimmt der Compiler einen String (der Länge 1) an und beginnt zu meckern. Anschließend kann man sich den String einmal komplett klein geschrieben und einmal komplett großgeschrieben ansehen.

nach oben

8. Umwandlung von primitiven Datentypen in Strings

Zuletzt wollen wir noch einen kurzen Blick auf die Möglichkeiten zur Konvertierung von primitiven Datentypen in Strings werfen:

public static String valueOf(int i)

Die Methode valueOf ist wieder eine statische Klassenmethode und kann unabhängig von der Existenz eines String-Objekts aufgerufen werden, da sie ja in aller Regel erst ein String-Objekt erzeugt, durch ihren Rückgabewert. Sie dient dazu, primitive Datentypen in Strings umzuwandeln (den umgekehrten Fall werden wir sehr bald kennen lernen). Natürlich kann man mit dieser Methode nicht nur Integer-Ganzzahlen in Strings umwandeln, sondern auch primitive Datentypen sowie Objekte oder ein Array aus "char". Folgendes Beispiel wandelt eine Fließkommazahl in einen String um:

double zahl = 3.56;
String text = String.valueOf(zahl);

Bisher haben wir desöfteren Ganz- und Kommazahlen einfach mit einem String über den +-Operator verbunden, z.B. bei der Bildschrimausgabe. Dabei werden sie automatisch in Strings umgewandelt und mit den anderen Strings verbunden. Weitere Methoden erlauben die Konvertierung eines Strings in ein Array aus "byte" oder "char", sie sind aber für uns im Moment eher unbedeutend. Interessierte entnehmen die Definitionen dieser Methoden der Java-Doku.

nach oben

9. Übung

Gegeben sei folgender String:

String chinesen = "Drei Chinesen mit dem Kontrabass";

  1. Erzeuge daraus folgenden Satz: "Drii Chinisin mit dim Kintribiss"
  2. Entferne nacheinander alle Wörter aus dem Satz, beginnend von hinten. Lasse den immer kleiner werdenden Satz jeweils zur Kontrolle ausgeben.

nach oben

10. Lösung

public class DreiChinesen {

  public static void main(String[] args) {
    String chinesen = "Drei Chinesen mit dem Kontrabass";
    
    // Vokale ersetzen
    chinesen = chinesen.replace('a', 'i');
    chinesen = chinesen.replace('e', 'i');
    chinesen = chinesen.replace('o', 'i');
    chinesen = chinesen.replace('u', 'i');
    System.out.println(chinesen);
    
    // Satz abschneiden
    int pos;
    while((pos = chinesen.lastIndexOf(" ")) != -1) {
      chinesen = chinesen.substring(0, pos);
      System.out.println(chinesen);
    }
  }

}

Das Ersetzen der Vokale ist ziemlich einfach. Schwieriger wird es, den Satz sukzessive abzuschneiden. Hierzu verwende ich eine while-Schleife: diese wird solange durchlaufen, wie die String-Methode "lastIndexOf" (sucht das jeweils letzte Vorkommen eines Leerzeichens) nicht -1 ergibt. In diesem Fall w"re kein Leerzeichen mehr gefunden worde, was bedeutet, dass nur noch ein Wort im Satz steht und man nicht weiter abschneiden kann. Die Schleife wird dann übersprungen.
Ein oft verwendeter Trick, um sich Schreibarbeit zu sparen: in der Bedingung der while-Schleife weisen wir das Ergebnis von "lastIndexOf" sofort der Variable "pos" zu. Das ist legitim, und die Variable "pos" steht auch in der Schleife zur Verfügung. So können wir dann mit der Methode "substring" einen Teilstring extrahieren, der vom Anfang des Strings (Index 0) bis zum Index "pos" reicht, also dem letzten Vorkommen eines Leerzeichens im Satz. So wird der Satz schrittweise verkürzt.

Eleganter ist es, die Einzelaufgaben in Methoden auszulagern:

public class DreiChinesen {

  public static String vokaleErsetzen(String chinesen) {
    chinesen = chinesen.replace('a', 'i');
    chinesen = chinesen.replace('e', 'i');
    chinesen = chinesen.replace('o', 'i');
    chinesen = chinesen.replace('u', 'i');
    return chinesen;
  }
  
  public static void satzAbschneiden(String chinesen) {
    int pos;
    while((pos = chinesen.lastIndexOf(" ")) != -1) {
      chinesen = chinesen.substring(0, pos);
      System.out.println(chinesen);
    }
  }

  public static void main(String[] args) {
    String chinesen = "Drei Chinesen mit dem Kontrabass";
    chinesen = vokaleErsetzen(chinesen);
    System.out.println(chinesen);
    satzAbschneiden(chinesen);
  }

}

nach oben