<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Strings revisited
Vorbemerkung
In diesem Notebook verwenden wir den Text "Der Mann von vierzig Jahren" von Jakob Wassermann. Dieser Text stammt aus dem Jahr 1913 und wurde vom Projekt Gutenberg digitalisiert (http
Step1:  str als Sequenztyp
Wie haben bereits den Datentyp str kennengelernt und uns mit Sequenztypen wie list beschäftigt. Da auch str ein Sequenztyp ist, stellten Strings ähnliche Schnittstellen bereit wie andere Sequenztypen. Wir können die Länge des Strings mit der Funktion len() ermitteln
Step2:  Mit dem in Operator können wir feststellen ob ein Zeichen oder ein Substring im String enthalten ist. Gibt es im Text ein Y?
Step3:  Kommt das Wort "Brandung" im Text vor?
Step4:  Substrings zählen
So wie man mit der count()-Methode zählen kann, wie oft ein Wert in einer Liste oder einem Tupel erscheint, kann auch gezählt werden, wie oft ein Zeichen oder eine Abfolge von Zeichen in einem String vorkommen
Step5:  Position ermitteln
Manchmal ist es nützlich, festzustellen, an welcher Position ein bestimmtes Zeichen oder ein Teilstring erstmalig vorkommt.
Step6:  Übung
Step7:  Übung
Step8:  Teilstrings ersetzen
In Python kann ganz einfach jedes Vorkommen eines Teilstrings durch einen anderen Teilstring ersetzt werden. Die entsprechende Methode ist .replace(alt, neu).
Step9:  Wir können uns das zunutze machen, um im Wassermann-Text alle nicht benötigten Zeilenumbrüche zu entfernen.
Step10:  Allerdings müssen wir hier etwas aufpassen
Step11:  Strings an bestimmten  Zeichen aufsplitten
Die Methode split() trennt einen String an jedem Whitespace und liefert eine Liste von Teilstrings.
Step12:  Damit haben wir einen primitiven Tokenizer, der unseren Text in einzelne Wörter zerlegt.
Übung
Step13:  Falls nicht an jedem Trennzeichen gesplittet werden soll, sondern z.B. nur beim ersten, kann maxsplit gesetzt werden. Falls wir also nur am ersten Satz interessiert sind
Step14:  Übung
Step15:  Es wäre schön, wenn hier jedes Wort nur einmal erscheinen würde. Wie das geht, wissen wir ja schon
Step16:  Stopwords
In der Datei data/stopwords_de.txt haben wir eine Liste mit Stopwords für die deutsche Sprache. Versuchen, wir, unsere Tokens um diese Wörter zu bereinigen. Dazu müssen wir zuerst die Stopwort-Liste einlesen
Step17:  Um nun die Stopwords aus der Liste tokens zu entfernen, können wir eine List Comprension verwenden
Step18:  Strings bauen mit format()
Um Variablen in Strings einzubauen kennt Python mehrere Möglichkeiten. Die zur Zeit empfohlene ist die Methode format(), die wir schon mehrfach verwendet haben. Die Idee dahinter ist, dass man in einen String Platzhalter einstreut, die mit format() befüllt werden.
Step19:  Falls wir einen Wert mehrfach benötigen, können wir die Platzhalter durchnummerieren
Step20:  Wir können die Platzhalter aber auch benennen
Step22:  Auf diese Weise ist es relativ einfach, einen Märchengenerator zu schreiben
<ASSISTANT_TASK:>
Python Code:
# TODO
Explanation: Strings revisited
Vorbemerkung
In diesem Notebook verwenden wir den Text "Der Mann von vierzig Jahren" von Jakob Wassermann. Dieser Text stammt aus dem Jahr 1913 und wurde vom Projekt Gutenberg digitalisiert (http://www.gutenberg.org/ebooks/15736). Um die Arbeit mit dem Text zu erleichtern, habe ich die Metadaten und Copyright-Hinweise aus dem Text entfernt und in eigene Dateien ausgelagert. Die vollständige Fassung ist unter der oben angeführten Adresse abrufbar. Die Gutenberg-Lizenz erfordert die Angabe des folgendes Textes:
This eBook is for the use of anyone anywhere at no cost and with almost no restrictions whatsoever.  You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this eBook or online at www.gutenberg.net
Übung: Wir wollen den gesamten Inhalt des Romans ein einen einzigen String mit dem Namen text einlesen. Die einzulesende Datei ist data/wassermann/der_mann_von_vierzig_jahren.txt.
End of explanation
# TODO
Explanation: str als Sequenztyp
Wie haben bereits den Datentyp str kennengelernt und uns mit Sequenztypen wie list beschäftigt. Da auch str ein Sequenztyp ist, stellten Strings ähnliche Schnittstellen bereit wie andere Sequenztypen. Wir können die Länge des Strings mit der Funktion len() ermitteln:
End of explanation
'Y' in text
Explanation: Mit dem in Operator können wir feststellen ob ein Zeichen oder ein Substring im String enthalten ist. Gibt es im Text ein Y?
End of explanation
# TODO
Explanation: Kommt das Wort "Brandung" im Text vor?
End of explanation
text.count('Brandung')
Explanation: Substrings zählen
So wie man mit der count()-Methode zählen kann, wie oft ein Wert in einer Liste oder einem Tupel erscheint, kann auch gezählt werden, wie oft ein Zeichen oder eine Abfolge von Zeichen in einem String vorkommen:
End of explanation
text.index('Brandung')
Explanation: Position ermitteln
Manchmal ist es nützlich, festzustellen, an welcher Position ein bestimmtes Zeichen oder ein Teilstring erstmalig vorkommt.
End of explanation
text.count('genau')
text.count('Genau')
Explanation: Übung: Wie könnten wir ermitteln, wo das zweite Vorkommen des Wortes Brandung beginnt?
Ähnlich wie index() das erste Vorkommen eines Zeichens oder Teilstrings ermittelt, kann mit rindex() das letzte Vorkommen gefunden werden.
Groß- und Kleinschreibung ändern
Die Methode upper() wandelt alle Zeichen eines Strings in Großbuchstaben um. lower() wandelt alle Zeichen in Kleinbuchstaben um.
Der vermutlich häufigste Einsatzzweck von upper() und lower() liegt darin, unabhängig von Groß- und Kleinschreibung im Text suchen zu können.
End of explanation
# TODO
Explanation: Übung: Überlegen Sie, wie alle Vorkommen von 'Genau' und 'genau' mit einer count() gefunden werden könnten.
Erzeugen Sie eine Variante von text, die nur Kleinbuchstaben enthält, und die unter dem Namen lc_text verfügbar gemacht wird.
End of explanation
s = 'Mississippi'
s.replace('s', 'b')
Explanation: Teilstrings ersetzen
In Python kann ganz einfach jedes Vorkommen eines Teilstrings durch einen anderen Teilstring ersetzt werden. Die entsprechende Methode ist .replace(alt, neu).
End of explanation
text.replace('\n', ' ')
Explanation: Wir können uns das zunutze machen, um im Wassermann-Text alle nicht benötigten Zeilenumbrüche zu entfernen.
End of explanation
# TODO
Explanation: Allerdings müssen wir hier etwas aufpassen: Absätze werden durch zwei aufeinander folgende Zeilenumbrüche gekennzeichnet. Wenn wir die Absätze erhalten wollen, dürfen wir nur einfache Zeilenumbrüche durch ein Leerzeichen entfernen. Hat jemand eine Lösung dafür?
End of explanation
tokens = lc_text.split()
tokens[:20]
Explanation: Strings an bestimmten  Zeichen aufsplitten
Die Methode split() trennt einen String an jedem Whitespace und liefert eine Liste von Teilstrings.
End of explanation
sentences = text.split('.')
Explanation: Damit haben wir einen primitiven Tokenizer, der unseren Text in einzelne Wörter zerlegt.
Übung: Aus wie vielen Tokens (Wörtern) besteht der Text?
Übung: Aus wie vielen Types besteht der Text? (Types sind unterschiedliche bzw. distinkte Tokens - man verwirft mehrfach vorkommende Tokens)
Übung: wie hoch ist die Type-Token-Ratio?
An Nicht-Whitespace splitten
Falls nicht an Whitespace, sondern an einem anderen Zeichen gesplittet werden soll, kann dieses Zeichen (oder eine Zeichenkette) angegeben werden. Wenn wir von der naiven Annahme ausgehen, dass jeder Satz durch einen Punkt begrenzt wird, können wir den Text so in Sätze zerlegen:
End of explanation
text.split('.', 1)
Explanation: Falls nicht an jedem Trennzeichen gesplittet werden soll, sondern z.B. nur beim ersten, kann maxsplit gesetzt werden. Falls wir also nur am ersten Satz interessiert sind:
End of explanation
[token for token in tokens if token.startswith('ab')]
Explanation: Übung: Splitten Sie den Text absatzweise.
Vergleichmethoden
Das String-Objekt kennt eine Reihe von Methoden, über die sich Stringvergleiche durchführen lassen.
startswith(str) und endswith(str) können dazu verwendet werden um Token zu finden, die mit einer bestimmten Zeichenfolge beginne oder enden. Die Token, die mit der Silbe ab beginnen finden wir so:
End of explanation
result = []
for token in tokens:
    # TODO
    pass
    
[token for token in tokens if token.isdigit()]
Explanation: Es wäre schön, wenn hier jedes Wort nur einmal erscheinen würde. Wie das geht, wissen wir ja schon:
Außerdem wollen wir die Ausgabe alphabetisch sortiert:
Die Token, die mit der Zeichenkette heit enden, können wir statt mit einer List Comprehension auch in einer Schleife suchen:
End of explanation
with open('data/stopwords_de.txt') as fp:
    stopwords = [word.rstrip() for word in fp.readlines()]
stopwords    
Explanation: Stopwords
In der Datei data/stopwords_de.txt haben wir eine Liste mit Stopwords für die deutsche Sprache. Versuchen, wir, unsere Tokens um diese Wörter zu bereinigen. Dazu müssen wir zuerst die Stopwort-Liste einlesen:
End of explanation
print(len(tokens)) 
tokens = [token for token in tokens if token not in stopwords]
len(tokens)
Explanation: Um nun die Stopwords aus der Liste tokens zu entfernen, können wir eine List Comprension verwenden:
End of explanation
print('Mein Name ist {}. Ich wohne in {}.'.format('Gunter', 'Graz'))
Explanation: Strings bauen mit format()
Um Variablen in Strings einzubauen kennt Python mehrere Möglichkeiten. Die zur Zeit empfohlene ist die Methode format(), die wir schon mehrfach verwendet haben. Die Idee dahinter ist, dass man in einen String Platzhalter einstreut, die mit format() befüllt werden.
End of explanation
print('Ihr Name ist {0}. Sie wohnen in {1}. Der Name "{0}" hat {2} Buchstaben'. format('Gunter', 'Graz', len('Gunter')))
Explanation: Falls wir einen Wert mehrfach benötigen, können wir die Platzhalter durchnummerieren:
End of explanation
print('Ihr Name ist {name}. Sie wohnen in {ort}. Der Name "{name}" hat {laenge} Buchstaben'. format(
    name='Gunter', ort='Graz', laenge=len('Gunter')))
Explanation: Wir können die Platzhalter aber auch benennen:
End of explanation
# Wir verwenden eine Zufallsgenerator zur Auswahl der Strings
import random
things = ['Kind', 'Pferd', 'Elch', 'Haus', 'Pirat', 'Gespenst',
          'Buch', 'Spiel', 'Stier', 'Ochse', 'Soldat', 'Bauer']
names = ['Stefan', 'Simon', 'Jakob', 'Moritz', 'Selma', 'Rita',
         'Mama', 'Oma', 'Papa', 'Opa']
places = ['Wald', 'Regenbogen', 'Kanal', 'Fluss', 'Knast',
          'Keller', 'Zoo']
print(Es war einmal ein {thing1}. Sein Name war {name1}.
{name1} liebte {name2}. {name2} war ein {thing2}.
{name1} und {name2} gingen in den {place1} und erlebten dort
viele Abenteuer.  Und wenn sie nicht gestorben sind, dann
leben sie noch heute..format(
    name1=random.choice(names), name2=random.choice(names),
    thing1=random.choice(things), thing2=random.choice(things),
    place1=random.choice(places)))
Explanation: Auf diese Weise ist es relativ einfach, einen Märchengenerator zu schreiben:
End of explanation
<END_TASK>