# Mit Zeichenketten arbeiten und manipulieren Diese Teilaufgaben sind teilweise sehr einfach zu implementieren und sollen veranschaulichen was man alles mit Strings machen kann. Hierbei könnt ihr euch es natürlich einfach machen und die Buildins von `str` verwenden oder die Funktionen komplett selber implementieren. ## String-Class Zunächst möchten wir eine *dataclass* *String* erstellen die genau einen *str* als Argument nimmt und in eimem privaten Attribut *__s* speichert. Dieses Attribut soll auch von Typ *str* sein und unsere *String* klasse intern representieren. ## Operatoren, Str, Len, und Iterator Nun möchten wir alle standard Operatoren und Funktionen für unseren *String* überschreiben ### `__str__` Diese Methode soll einfach die *str* Representation unserer *String* Klasse sein ### `__add__`, `__radd__` Diese Methode soll unseren *String* nicht verändern, aber zwei *Str* konkatenieren. Hierbei kann ein *Str* sowohl ein *String* als auch ein *str* sein! Hierbei wird `self` mit `other` konkateniert. `__radd__` hat genau das selbe verhalten, nur dass `other` mit `self` konkateniert wird. ```python my_string = String("hello") assert str(my_string + " world") == "hello world" assert str("world " + my_str) == "world hello" ``` ### `__len__` Diese Methode soll uns die Länge unseres Strings zurückgeben ```python assert len(String("hello world")) == 11 ``` ### `__eq__` Diese Methode soll die Vergleichbarkeit zwischen *str* und *String* implementieren, also ```python my_string = String("hello") assert my_string == "hello" assert my_string == String("hello") ``` ### `__iter__` Diese Methode soll einen Iterator aus unserem *String* machen damit wir über die einzelnen Characters iterieren können ```python my_string = String("hello world") my_it = iter(my_string) for c in my_it: print(c, end="") # hello world ``` ## `concat` Hierbei soll *self* nicht verändert werden, wir möchten *self* mit *other* konkatenieren und einen neuen konkatenierten *String* zurückgeben ## `contains` Wir möchten schauen ob *other* in *self* enthalten ist ## `substring` Wir möchten einen neuen *String* zurückgeben der alle Stellen von `start` bis `end`enthält. Hierbei sollten man von ausgehen dass `start` und `end` nicht negativ oder größer als der String sind. ## `strip` Wir möchten am Anfang und Ende des Strings alle Stellen entfernen, solang diese in `chars` enthalten sind. Also ```python assert String(" hello ").strip() == "hello" ``` ## `replace` Diese Methode soll überall `old` mit `new` genau `count`-Mal ersetzen. Wenn `count` negativ ist soll einfach jedes `old` ersetzt werden. ## `add_prefix`, `add_suffix` `add_prefix` soll einen Prefix zu unserem String konkatenieren und analog dazu soll `add_suffix` einen Suffix zu unserem String konkatenieren ## `join` Diese soll eine iterierbare Datenstruktur nehmen und zwischen jedes Element unseren *String* konkatenieren. Wir können davon ausgehen dass `T` zu einem *str* konvertiert werden kann (also `str(T)` anwendbar ist) ```python assert String(", ").join([1, 2, 3, 4, 5]) == "1, 2, 3, 4, 5" ```