Einleitung
Speicherverwaltung
string Iteratoren
Vergleichen von strings
Suchen in strings
Kopieren von strings und Teil-strings
Anhängen und Ersetzen in strings
Einfügen und Entfernen in strings
Beispiel und Übung
Bevor wir beginnen, noch einmal zur Erinnerung: Die Klasse string liegt im Namensraum std::, der in dieser Lektion nicht explizit angegeben wird!
Die Klasse string haben Sie ja bisher schon öfters eingesetzt. Wir werden uns in der Lektion diese Klasse jetzt einmal genauer ansehen. Im Folgenden wird davon ausgegangen, dass Sie wissen wie string Objekte definiert werden, wie strings eingelesen und ausgegeben werden und dass Sie die string Operatoren =, + sowie die Vergleichsoperationen kennen. Hier können Sie sich diese Grundvoraussetzungen nochmals ansehen.
Bisher haben wir der Einfachheit halber immer nur Objekte der Klasse string verwendet. string verwendet zur Speicherung der Zeichen den Datentyp char. Um auch Zeichen mit dem Datentyp wchar_t ablegen zu können, gibt es zusätzlich noch die Klasse wstring.
#include <string> std::string charString; std::wstring wcharString; |
Da string und wstring die gleichen Eigenschaften und Schnittstellen besitzen, wird im Folgenden nicht mehr zwischen diesen beiden string-Typen unterschieden.
Der von einem string Objekt letztendlich belegte Speicher wurde bei den bisherigen Ausführungen nicht betrachtet. Da in manchen Fällen aber der Speicherplatz eine nicht zu vernachlässigende Rolle spielt, wollen wir dies an dieser Stelle jetzt nachholen.
Zur Ermittlung des von einem String belegten Speicherplatzes stehen die Memberfunktionen size(), length() und capacity() zur Verfügung.
size() und length() sind identischen Memberfunktionen; sie liefern die Anzahl der in einem String abgelegten Zeichen. capacity() hingegen liefert die Anzahl der Zeichen zurück die in einem String abgelegt werden können, ohne dass erneut Speicher angefordert werden muss. Und dies muss nicht zwingend mit der Anzahl der Zeichen im String übereinstimmen. Sehen Sie dazu einmal die nachfolgenden Anweisungen sowie die dazugehörigen Ausgaben an. Wie Sie der Ausgabe entnehmen können, verändert sich nach der zweiten Zuweisung nur die Länge des Strings, nicht aber die Anzahl der Zeichen im String ohne erneute Speicheranforderung.
string myString = "123456789"; cout << myString.length() << ',' << myString.capacity() << endl; myString = "12"; cout << myString.length() << ',' << myString.capacity() << endl; |
|
9,15 |
Je nach Compiler, können Sie andere Werte erhalten. Aber die grundsätzliche Aussage bleibt die gleiche: der von einem String einmal belegte Speicherplatz wird in der Regel aus Gründen der Ausführungsgeschwindigkeit (Performance) nicht mehr vermindert. Dies bedeutet in der Praxis, dass ohne weiteres Zutun der von einem String belegte Speicherplatz immer nur anwächst.
Um die zeitintensive Speicheranforderung für eine Stringerweiterung zu minimieren, stellt die string Klasse eine Memberfunktion reserve(...) zur Verfügung. reserve(...) erhält als Parameter die Anzahl der Zeichen, für die minimal Speicher in einem String zu reservieren sind. Wenn Sie also die maximale Länge eines String im Voraus wissen, so können Sie mithilfe dieser Memberfunktion gleich von Anfang an genügend Speicher reservieren und somit die zeitintensiven Speicheranforderungen umgehen. Wird reserve() ohne Parameter aufgerufen, so wird der für den String belegte Speicherplatz so bemessen, dass der aktuelle Stringinhalt darin Platz findet. Je nach Implementierung der string Klasse kann damit eine Reduzierung des Speicherplatzverbrauchs erreicht werden.
|
|
Bei einigen nachfolgenden string-Operationen werden so genannte Iteratoren eingesetzt. Iteratoren im Allgemeinen werden erst später im Kurs behandelt. Für den Augenblick können Sie sich unter einem Iterator einen Positionsindikator vorstellen, der auf eine beliebige Position innerhalb des Strings verweist. Der String-Iterator ist quasi das C++ Gegenstück zum char-Zeiger in C-Strings. Beachten Sie bitte, dass auch die String-Iteratoren, genauso wie der string selbst, im Namensraum std liegen.
Fangen wir mit der Definition eines Iterators an. Nachfolgend sehen Sie die Definition des String-Iterators iter.
// Definition eines String-Iterators
string::iterator iter;
|
Und was für 'normale' Zeiger gilt, gilt auch für Iteratoren: sie müssen nach ihrer Definition unbedingt initialisiert werden. Für die Initialisierung von Iteratoren stehen die string-Memberfunktionen begin() und end() zur Verfügung. begin() liefert einen Iterator auf den Anfang des Strings und end() einen Iterator auf die nächste Position hinter dem String, d.h. begin() und end() definieren einen offenen Bereich [...).
string myString("12345");
// Iterator auf Stringanfang setzen
iter = myString.begin();
// Iterator auf Stringende+1 setzen
iter = myString.end();
|
Um auf das Zeichen zuzugreifen, auf das der Iterator verweist, wird der Iterator (genauso so wie Zeiger) einfach dereferenziert. Und es besteht noch eine Gemeinsamkeit zwischen Zeigern und Iteratoren: auch auf Iteratoren sind nur die Operationen Addition und Subtraktion sowie Vergleichsoperationen erlaubt.
// String zeichenweise ausgeben
for (iter=myString.begin(); iter!=myString.end(); ++iter)
cout << *iter << ',';
|
Das obige Beispiel gibt den Inhalt des String-Objekts myString zeichenweise aus. Beachten in der for-Schleife das Abbruch-Kriterium! end() liefert einen Iterator der hinter das letzte Zeichen im String 'zeigt'.
Außer diesem 'normalen' Iterator gibt es noch einen Reverse-Iterator. Er erlaubt es, einen String rückwärts zu durchlaufen. Beachten Sie im nachfolgenden Beispiel, dass nun anstelle von begin() und end() die Memberfunktionen rbegin() und rend() verwendet werden. Um den Iterator auf das vorhergehende Zeichen zu positionieren, müssen Sie den Iterator weiterhin inkrementieren!
// Reverse-Iterator definieren string::reverse_iterator riter; // String rückwärts ausgeben for (riter=myString.rbegin(); riter!=myString.rend(); ++riter) cout << *riter << ','; |
|
|
|
|
|
|
Den 'üblichen' Vergleich von Strings mithilfe von Vergleichsoperatoren kennen Sie ja schon aus einer der vorherigen Lektionen. Als Ergebnis des Vergleichs erhalten Sie entweder true oder false. Hier können Sie sich dies nochmals ansehen.
// Strings definieren string s1("abc"), s2("xyz"); // Vergleich mit Vergleichsoperatoren bool ret = s1<s2; |
Zusätzlich bietet die string Klasse für Vergleiche auch noch die Memberfunktion compare(...) an. compare(...) erhält im einfachsten Fall als Parameter das zu vergleichende string Objekt oder einen const char Zeiger auf einen C-String. Als Returnwert liefert compare(...) einen int-Wert, der '0' ist, wenn beide Strings den gleichen Inhalt haben, <0 wenn der übergebene (zu vergleichende) String größer ist und >0 wenn er kleiner ist.
|
|
Aber das ist noch nicht alles, was die Memberfunktion compare(...) kann. compare(...) kann auch dazu verwendet werden, Teile eines Strings zu vergleichen. Dazu stehen folgenden Memberfunktionen zur Verfügung:
|
Vergleich den Teilstring mit der Länge len ab der Position pos mit den zweiten String s2. |
int compare (size_type pos,
size_type len,
const string& s2,
size_type pos2,
size_type len2) const;
|
Vergleich den Teilstring mit der Länge len ab der Position pos mit dem zweiten Teilstring s2 mit der Länge len2 ab der Position pos2. |
int compare (size_type pos,
size_type len,
const char* pstr) const;
|
Vergleich den Teilstring mit der Länge len ab der Position pos mit dem C-String, auf den pstr verweist. |
int compare (size_type pos,
size_type len,
const char* pstr,
size_type len2) const;
|
Vergleich den Teilstring mit der Länge len ab der Position pos mit len2 Zeichen aus dem C-String, auf den pstr verweist. |
|
|
Das nachfolgende Beispiel zeigt exemplarisch den Einsatz der compare(...) Memberfunktion auf. Innerhalb eines in einem string abgelegten Textes wird auf das Vorkommen eines bestimmten Textes ab einer definierten Stelle abgeprüft. Beachten Sie bitte, dass der Text an einer bestimmten Stelle stehen muss, compare(...) durchsucht nicht den komplette String. Hierzu dienen Memberfunktionen die gleich noch vorgestellt werden.
// Zu prüfender Text string test1("Sehr geehrte Frau Ypsilon"); // Prüfen ob Empfänger männlich/weiblich if (test2.compare(12,5," Frau") == 0) cout << "Empfänger ist weiblich" << endl; else cout << "Empfänger ist männlich" << endl; |
Zum Suchen von Zeichen und Strings innerhalb von string stehen über 40 verschiedene Memberfunktionen zur Verfügung. Aber keine Angst, wir werden uns hier nicht alle Memberfunktionen ansehen, sondern nur deren 'Grundformen'. So erlauben die meisten Memberfunktionen die Angabe des Suchkriteriums entweder als string oder als C-String.
Alle Such-Memberfunktionen haben als Rückgabetyp den Datentyp string::size_type.
Bei der Suche innerhalb eines Strings kann es vorkommen, dass ein gesuchtes Zeichen bzw. ein gesuchter String im zu untersuchenden String nicht vorhanden ist. In diesem Fall liefern alle Such-Memberfunktionen den Wert string::npos zurück (siehe auch nachfolgendes Beispiel).
Zum Suchen von Zeichen stehen die Memberfunktionen find(...) und rfind(...) zur Verfügung. Beide Memberfunktionen erhalten das zu suchende Zeichen als Parameter übergeben. find(...) sucht nach dem ersten Auftreten des Zeichens und rfind(...) nach dessen letztem. Als Returnwert liefern die Memberfunktionen die Position des gesuchten Zeichens im String. Die Positionsangabe ist 0-basierend. Ist das Zeichen nicht im String vorhanden, so wird, wie bereits erwähnt, string::npos zurückgeliefert.
// Zu durchsuchender String string path("c:/corba/doc/readme.doc"); // Suche nach erstem Slash string::size_type first = path.find('/'); // Suche nach letztem Slash string::size_type last = path.rfind('/'); // Suche nach nicht vorhandenem Zeichen if (path.find("X") == string::npos) cout << "Zeichen X nicht gefunden". |
Zum Suchen nach einem Teilstring werden ebenfalls die Memberfunktionen find(...) und rfind(...) verwendet. Beide Memberfunktionen erhalten den zu suchenden String entweder als string oder C-String (const char*) übergeben. find(...) sucht wieder nach dem ersten Auftreten der Zeichenfolge und rfind(...) nach dem letzten. Als Returnwert liefern die Memberfunktionen die Position des gesuchten Strings im String.
// Zu durchsuchender String string path("c:/corba/doc/readme.doc"); // Suche nach erstem Teilstring string::size_type first = path.find("doc"); // Suche nach Laufwerkstrenner string toTest(":/"); string::size_type last = path.rfind(toTest); |
Ein String kann auch auf das Vorkommen eines Zeichens aus einer Zeichenmenge durchsucht werden. Hierzu dienen die Memberfunktionen find_first_of(...) und find_first_not_of(...). Beide Memberfunktionen erhalten als Parameter einen String übergeben, der die Zeichenmenge enthält. find_first_of(...) liefert die Position zurück, an der ein beliebiges Zeichen aus der Zeichenmenge im String das erste Mal auftritt. find_first_not_of(...) hingegen liefert als Returnwert die Position, an der das erste nicht in der Zeichenmenge vorhandene Zeichen auftritt. Im Beispiel unten liefert find_first_of(..) die Position des ersten Kleinbuchstabens (hier 1) und find_first_not_of(...) die Position des ersten 'Nicht-Buchstabens' (hier 11, Ziffer 2 in der Zahl 23).
// Zeichenmengen definieren string lowerChar("abcdefghijklmnopqrstuvwxyz"); string upperChar("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); string anyChar(lowerChar+upperChar+' '); // Zu durchsuchender String string street("Lerchenweg 23"); // Suchen nach dem ersten Kleinbuchstaben string::size_type pos = street.find_first_of(lowerChar); // Suche nach dem ersten Nicht-Buchstaben pos = street.find_first_not_of(anyChar); |
Während die find_first_xx(...) Memberfunktionen nach dem ersten (nicht-) Auftreten eines Zeichens aus einer Zeichenmenge suchen, so suchen die Memberfunktionen find_last_of(...) bzw. find_last_not_of(...) nach dem letzten (nicht-) Auftreten eines Zeichens aus der Zeichenmenge. Im Beispiel liefert find_last_of(...) die Position 9 zurück, da 'g' der letzte Kleinbuchstabe im String ist. find_last_not_of(...) liefert die Position 12 zurück, da die Ziffer 3 (aus der Zahl 23) der letzte 'Nicht-Buchstabe' im String ist.
// Zeichenmengen definieren string lowerChar("abcdefghijklmnopqrstuvwxyz"); string upperChar("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); string anyChar(lowerChar+upperChar+' '); // Zu durchsuchender String string street("Lerchenweg 23"); // Suchen nach dem letzten Kleinbuchstaben string::size_type pos = street.find_last_of(lowerChar); // Suche nach dem letzten Nicht-Buchstaben pos = street.find_last_not_of(anyChar); |
Damit wollen wir es an dieser Stelle bewenden lassen. Alle hier vorgestellten Memberfunktionen haben, wie bereits erwähnt, noch weitere Formen die es erlauben, zum Beispiel auch einen C-String als Suchkriterium bzw. als Zeichenmenge anzugeben.
Das Kopieren eines strings in einen anderen string erfolgt (wie üblich) mit dem Zuweisungsoperator. Was wir uns an dieser Stelle näher ansehen werden ist, wie Sie den Inhalt eines strings in ein char-Feld umkopieren können.
|
|
Wollen Sie den Inhalt eines strings in ein char-Feld umkopieren, um diesen dann anschließend verändern zu können, so verwenden Sie hierzu die Memberfunktion copy(...). copy(...) erhält als ersten Parameter einen Zeiger auf den Speicherbereich, in dem der String-Inhalt abgelegt werden soll und als zweiten Parameter die max. Anzahl der zu kopierenden Zeichen aus dem String. Als Returnwert liefert die Memberfunktion die tatsächliche Anzahl der kopierten Zeichen.
// String definieren string street("Lerchenweg 23"); // char-Feld definieren char buffer[80]; // String in char-Feld umkopieren string::size_type len = street.copy(buffer,sizeof(buffer)); // C-String mit 0 abschliessen! buffer[len] = 0; |
|
|
Es steht außerdem noch eine zweite copy(...) Memberfunktion zur Verfügung, die es gestattet, nur Teile innerhalb eines Strings umzukopieren. Dazu erhält die Memberfunktion als dritten Parameter die Anfangsposition innerhalb des Strings, ab der kopiert werden soll.
Die Memberfunktion copy(...) kopiert aber immer ab der angegebenen Anfangsposition innerhalb des Strings bis zu dessen Ende um. Um aus einem String einen Teilstring zu extrahieren wird die Memberfunktion substr(...) eingesetzt. Im Gegensatz zu copy(...) wird der extrahierte Teilstring aber nicht in einem char-Feld abgelegt sondern in einem weiteren string, der als Returnwert von substr(...) zurückgeliefert wird.
Wird substr() ohne Parameter aufgerufen, so wird der komplette String in einen neuen String umkopiert. Um einen Teilstring zu extrahieren, rufen Sie substr(...) auf und geben als ersten Parameter die Anfangsposition an, ab der die Zeichen kopiert werden sollen und als zweiten Parameter die Anzahl der zu kopierenden Zeichen (1. Aufruf von substr(...) im nachfolgenden Beispiel). Als Alternative können Sie auch den zweiten Parameter weglassen, in diesem Fall wird aber der Anfangsposition bis zum Ende alles extrahiert (2. Aufruf von substr(...)). Das Beispiel extrahiert aus dem String street zum Beispiel den Straßennamen in den String part1 und in den String part2 die Hausnummer. Leerzeichen zwischen dem Straßennamen und der Hausnummer werden dabei explizit übersprungen.
// Strings definieren string street("Lerchenweg 23"); string lowerChar("abcdefghijklmnopqrstuvwxyz"); string upperChar("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); string anyChar(lowerChar+upperChar); // Suche nach erstem 'Nicht-Buchstaben' string::size_type pos = street.find_first_not_of(anyChar); // Strassennamen extrahieren string part1 = street.substr(0,pos); // Hausnummer extrahieren string part2 = street.substr(pos+1); |
Zum Anhängen von Zeichen an einen String stehen ebenfalls diverse Memberfunktionen zur Verfügung, von denen wir uns an dieser Stelle nur die beiden wichtigsten ansehen werden. Mehr dazu entnehmen Sie bitte der Online-Hilfe.
Soll ein einzelnes Zeichen an einen String angefügt werden, so können Sie dies mithilfe des Operators += tun.
Um mehrere gleiche Zeichen an einen String anzuhängen, wird die Memberfunktion append(...) verwendet. Der erste Parameter gibt die Anzahl der anzufügenden Zeichen an und der zweite Parameter das Zeichen.
string myString("bla bla bla");
// Ein Ausrufezeichen anhängen
myString += '!';
// 5 Fragezeichen anhängen
myString.append(5,'?');
|
Zum Anfügen von kompletten Strings kann u.a. auch der Operator += verwendet werden. Ebenfalls kann die Memberfunktion append(...) hierfür verwendet werden. append(...) erlaubt es auch, einen Teilstring aus einem anderen String oder C-String anzuhängen. Dazu erhält append(...) dann als ersten Parameter den String, aus dem die Zeichen angefügt werden sollen, als zweiten Parameter die Startposition innerhalb dieses Strings und danach die Anzahl der anzuhängenden Zeichen.
string string1("eins zwei ");
string string2("drei vier fuenf");
// Komplette strings2 anfügen
string1 += string2;
// C-String anfügen
string1.append("...");
// Teilstring aus string2 anfügen
string1.append(string2,5,4);
|
Um Zeichen oder eine Zeichenfolgen innerhalb eines Strings zu ersetzen, wird die Memberfunktion replace(...) verwendet. replace(...) kann dabei ein oder mehrere Zeichen ab einer bestimmten Position durch ein oder mehrere andere Zeichen ersetzen. Die ersetzende Zeichenfolge kann dabei entweder als String oder als C-String angegeben werden. Im Beispiel hat der String gruss am Schluss den Inhalt 'Guten Morgen Frau Maier'.
string gruss("Hallo #");
string anrede("Frau Maier");
const char* morgen = "Guten Morgen";
// Nach Zeichen # suchen
string::size_type pos = gruss.find('#');
// und durch den String anrede ersetzen
gruss.replace(pos,anrede.length(),anrede);
// 'Hallo' durch den C-String morgen ersetzen
gruss.replace(0,5,morgen,strlen(morgen));
|
Zum Einfügen von Zeichenfolgen dient die Memberfunktion insert(...). Insgesamt stehen auch hier wieder 8 verschiedene Formen dieser Memberfunktion zur Verfügung. Alle Memberfunktionen erhalten als ersten Parameter den Index, ab der das einzufügende Zeichen bzw. die einzufügende Zeichenfolge einzufügen ist. Das Beispiel fügt das Wort drei zwischen den Wörtern zwei und vier ein.
// String definieren string s1("eins zwei vier"); // Position von 'vier' suchen string::size_type pos = s1.find("vier"); // und davor 'drei ' einfügen s1.insert(pos,"drei "); |
Da man sich in der Regel sowieso nicht alle Formen der insert(...) Memberfunktion merken kann, sei an dieser Stelle auf die Online-Hilfe verwiesen.
Sehen wir uns zum Abschluss noch an, wie Zeichen bzw. Zeichenfolgen aus einem String entfernt werden können.
Um den kompletten Inhalt eines Strings zu löschen, wird die Memberfunktion clear() verwendet. Ob dabei auch der bisher durch den String belegten Speicher freigegeben wird ist implementierungsabhängig. Definiert ist einzig und allein, dass der String danach leer ist.
string s1("Guten Tag");
....
// String-Inhalt löschen
s1.clear();
|
Sollen nur Teile eines Strings entfernt werden, so ist hierfür die Memberfunktion erase(...) einzusetzen. Auch hiervon gibt es mehrere Formen. Allen gemeinsam ist, dass sie im ersten Parameter die Startposition erhalten, ab der gelöscht wird. Wird ein zweiter Parameter angegeben, so legt er die Anzahl der zu löschenden Zeichen fest. Im Beispiel wird das Wort wunderschoenen aus dem String s1 entfernt.
string s1("Einen wunderschoenen guten Morgen");
string toErase("wunderschoenen");
// Position des zu löschenden Strings suchen
string::size_type pos1 = s1.find(toErase);
// String nun entfernen
s1.erase(pos1,toErase.length()+1);
|
Beenden wir damit die Übersicht über die Klasse string. Sie sollten sich aber auf jeden Fall auch einmal die Online-Hilfe zu dieser Klasse ansehen. Dort finden Sie die Beschreibungen der Memberfunktionen unter der Klasse basic_string. string selbst ist nur eine Spezialisierung von basic_string in der Form, dass string char Elemente verarbeitet. Eine andere Form ist wstring zur Verarbeitung von Elementen vom Typ wchar_t.
|
| Hallo # % schoen dass Sie diese Uebung durchfuehren wollen. # %, wenn Sie diese Uebung richtig durchgefuehrt haben, dann sollte jetzt Ihr Name, # %, im Text erscheinen. |
|
=== Orignal-Text war === schoen dass Sie diese Uebung durchfuehren wollen. # %, wenn Sie diese Uebung richtig durchgefuehrt haben, dann sollte jetzt Ihr Name, # %, im Text erscheinen. === Korrgierter Text ist === schoen dass Sie diese Uebung durchfuehren wollen. Frau Maier, wenn Sie diese Uebung richtig durchgefuehrt haben, dann sollte jetzt Ihr Name, Frau Maier, im Text erscheinen. Mit freundlichen Gruessen |
// Beispiel zu String(2) // Dateien einbinden #include <iostream> #include <fstream> #include <string> using std::cout; using std::endl; using std::string; // Zu verarbeitende Datei mit Serienbrieftext const char *pFILE = "sbrief.txt"; // main() Funktion int main() { // Datei öffnen string serienBrief; std::ifstream inFile(pFILE); if (!inFile) { cout << "Fehler beim Öffnen der Datei " << pFILE << endl; return 1; } // Komplette Datei in einen string einlesen while (!inFile.eof()) { string line; // Zeile aus Datei einlesen std::getline(inFile,line); // und an String anhängen serienBrief += line; // Zeilenvorschub anhängen serienBrief += '\n'; } cout << "=== Orignal-Text war ===\n" << serienBrief << endl; // Alle '#' im Text durch Anrede ersetzen string::size_type pos = 0; do { pos = serienBrief.find('#',pos); if (pos != string::npos) serienBrief.replace(pos,1,"Frau"); } while (pos != string::npos); // Alle '%' im Text durch Namen ersetzen pos = 0; do { pos = serienBrief.find('%',pos); if (pos != string::npos) serienBrief.replace(pos,1,"Maier"); } while (pos != string::npos); // Nach jedem Punkt nun eine neue Zeile beginnen pos = 0; do { pos = serienBrief.find('.',pos); if (pos != string::npos) { serienBrief.insert(pos+1,"\n"); serienBrief.erase(pos+2,1); pos++; } } while (pos != string::npos); // Grussformel anhängen serienBrief.append("Mit freundlichen Gruessen\n"); cout << "=== Korrgierter Text ist ===\n" << serienBrief << endl; return 0; } |
Erstellen Sie eine Klasse SplitFullPath die es erlaubt, die vollständige Angabe einer Datei (bestehend aus Laufwerk, Pfad, Dateiname) in seine Einzelteile Laufwerk, Pfad und Dateiname zu zerlegen.
Die vollständige Angabe der Datei soll dabei als C-String wie auch als string-Objekt möglich sein.
Definieren Sie entsprechende Memberfunktionen, die das Laufwerk, den Pfad sowie den Dateinamen zurückliefern.
Zerlegen Sie die Dateinamen 'c:/userdata/temp/data.dat' in die Einzelteile. Ersetzen Sie im Dateinamen dann die ursprüngliche Extension durch die Extension bak.
|
Der zu zerlegende Dateiname ist: |