Einführung in das Programmieren mit Python

Werbung
2.5 Umgang mit Textdateien und Strings
Beim Abschlussprojekt Autorschaftstest müssen Texte, die in Dateien
gespeichert sind, verarbeitet werden.
Dazu gibt es jetzt ein paar Beispiele und Anmerkungen.
Strings
Pythons Datentyp string dient zum Speichern und Bearbeiten von
Zeichenfolgen.
Ein Strings ist zwar kein Array,
aber die üblichen Index-Operationen gehen auch mit Strings.
import stdio
# Strings kann man mit '...' oder "..." begrenzen.
a = 'abcde'
b = "12'45"
s = ''
for i in range(len(a)):
s = s + a[i] + b[-(i+1)]
stdio.writeln(s)
#------------------------------------------------------# python string1.py
# a5b4c'd2e1
2.5.1
Umlaute
Wenn man Kommentar mit Umlauten einfügt, gibt es eine Fehlermeldung.
import stdio
# Strings kann man mit '...' oder "..." begrenzen.
a = 'abcde'
b = "12'45"
s = ''
# Verschränke a vorwärts und b rückwärts ineinander.
for i in range(len(a)):
s = s + a[i] + b[-(i+1)]
stdio.writeln(s)
#------------------------------------------------------# python string1.py
# File "string1.py", line 9
# SyntaxError: Non-ASCII character '\xc3' in file string1.py on line 9, but no
#
encoding declared; see http://www.python.org/peps/pep-0263.html for details
2.5.2
Kodierung gemäß ASCII
ASCII ... American Standard Code for Information Interchange
Jedes Zeichen wird in einem Speicherwort aus 8 Bit gespeichert,
z.B. a durch 0110 0001 (dezimal 97, hexadezimal 61).
Davon werden 7 Bit benutzt – das reicht für 128 verschiedene Zeichen.
Umlaute sind nicht im ASCII-Code.
2.5.3
Kodierung gemäß UTF-8
UTF-8 ... 8-Bit Universal Character Set Transformation Format
ASCII Zeichen werden in UTF-8 wie in ASCII dargestellt (8 Bit).
Weitere Zeichen werden durch 2 Speicherwörter aus 8 Bit dargestellt,
z.B. ä durch 1100 0011 1010 0100 (hexadezimal c3a4).
Bei ASCII-Kodierung ist das erste Bit stets 0.
Wenn ein Zeichen mit UTF-8 durch mehrere Speicherwörter kodiert wird,
dann gibt die Anzahl der 1en am Anfang des ersten Wortes an, wieviele
Speicherwörter benutzt werden.
2.5.4
Umlaute
Also muss man ein encoding in den Programmtext einfügen, in dem Umlaute
enthalten sind (und das vom Editor beim Schreiben des Programms benutzt
wurde).
# encoding: utf-8
import stdio
# Strings kann man mit '...' oder "..." begrenzen.
a = 'abcde'
b = "12'45"
s = ''
# Verschränke a vorwärts und b rückwärts ineinander.
for i in range(len(a)):
s = s + a[i] + b[-(i+1)]
stdio.writeln(s)
#------------------------------------------------------# python string1.py
# a5b4c'd2e1
Umlaute in Strings
Wenn man Umlaute im String hat, gibt es eine andere Fehlermeldung.
# encoding: utf-8
import stdio
# Strings kann man mit '...' oder "..." begrenzen.
a = 'äbcde'
b = "12'45"
s = ''
# Verschränke a vorwärts und b rückwärts ineinander.
for i in range(len(a)):
s = s + a[i] + b[-(i+1)]
stdio.writeln(s)
#------------------------------------------------------# python string1.py
# Traceback (most recent call last):
#
File "string1.py", line 12, in <module>
#
s = s + a[i] + b[-(i+1)]
# IndexError: string index out of range
Also ist a jetzt länger als b!
(Und das ist nicht das einzige Problem . . . )
2.5.6
String ‘ä’ ist länger als String "a"
# encoding: utf-8
import stdio
stdio.writeln(len('ä'))
stdio.writeln(len('a'))
#------------------------------------------------------# python string2.py
# 2
# 1
2.5.7
Kann man Strings mit Umlauten indiziert durchlaufen?
# encoding: utf-8
import stdio
s = 'Lärm'
for i in range(len(s)):
stdio.writeln(s[i])
#------------------------------------------------------# python string3.py
# L
# Traceback (most recent call last):
#
File "string3.py", line 8, in <module>
#
stdio.writeln(a[i])
#
File "/usr/local/lib/python2.7/dist-packages/stdio.py", line 42, in writeln
#
x = unicode(x)
# UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not i
Mit print(a[i]) anstelle von stdio.writeln(s[i]) gibt es keine
Fehlermeldung, aber auch keine richtige Ausgabe.
2.5.8
Da hilft nur noch der Umstieg auf Python 3.
import stdio
s = 'Lärm'
for i in range(len(s)):
stdio.writeln(s[i])
#------------------------------------------------------# python3 string3.py
# L
# ä
# r
# m
Dort wird alles in UTF-8 gemacht.
2.5.9
Schreiben wie Goethe
Zufällige Texte erzeugen
Das Beispiel auf den folgenden Seiten führt zum Erzeugen eines zufälligen
Satzes. Dazu wird
§
eine Textdatei eingelesen (z.B. Goethes Faust oder Joyces Ulysses)
§
alle Paare von aufeinanderfolgenden Wörtern gefunden
§
ein Satz erzeugt, in dem jedes Paar aufeinanderfolgender Wörter
auch in der gelesenen Textdatei vorkommt.
Direktes Einlesen von Dateien
Man kann Dateien zeilenweise als Strings einlesen.
# einlesen.py
import sys, stdio, instream
def liesText(dateiname):
# Lies Datei dateiname ein und speichere sie in einem String (mittels readAll())
# instream.InStream() liest z.B. aus einer Datei und kann
# benutzt werden wie standard input.
text = instream.InStream(dateiname).readAll()
return text
#----------------------------------------------------------------------------------def test():
dateiname = sys.argv[1]
text = liesText(dateiname)
stdio.writeln(text)
#----------------------------------------------------------------------------------if __name__ == '__main__': test()
2.5.11
python3 einlesen.py SchillerBriefe3.txt
0 Sie haben durch den schönen Beitrag, den Sie in Ihrem _Dante_ zu den
1 Horen gegeben, ein zu entschiedenes Verdienst um den glücklichen
2 Fortgang dieses Journals, als dass ich Ihnen nicht den verbindlichsten
3 Dank dafür sagen sollte. Ich thue dieß um so lieber, da es mich zugleich
...
python3 einlesen.py http://www.gutenberg.org/cache/epub/7939/pg7939.txt
0 Project Gutenberg's Die Huldigung der Kuenste, by Friedrich Schiller
1 #41 in our series by Friedrich Schiller
2
3 Copyright laws are changing all over the world. Be sure to check the
4 copyright laws for your country before downloading or redistributing
5 this or any other Project Gutenberg eBook.
6
...
2.5.12
Die Funktion einstring(d) macht einen String aus der ganzen Datei.
# einlesen.py
import string
def einstring(dateiname):
# Lies Datei dateiname als einen (langen) String
datei = open(dateiname,"r")
text_als_ein_string = ''
for zeile in datei:
text_als_ein_string += string.rstrip(zeile)
datei.close()
return text_als_ein_string
def test():
taes = einstring("SchillerBriefe3.txt")
print taes
if __name__ == '__main__': test()
Die Funktion string.rstrip(z) entfernt Leerzeichen und
Zeilenumbrüche am Ende des Strings z.
2.5.13
Zerlegen eines Textes in Wörter
Die folgende Funktion zerlege.woerterliste(s)
§
erhält als Eingabe einen String s, der z.B. durch Einlesen eines
Textes aus einer Datei entstanden ist,
§
ersetzt alle Satzendezeichen durch . “
”
(dadurch wird der Punkt durch Leerzeichen vom Rest getrennt),
§
entfernt Zeichen aus dem String, die wir nicht brauchen, und
§
trennt den String an allen (Folgen von) Leerzeichen auf und erhält
dadurch ein Array aus den Teilen des Strings (d.h. den Wörtern), die
zwischen zwei Leerzeichen stehen. In dem Array stehen die Wörter in
der gleichen Reihenfolge wie im Text.
Als Ergebnis wird das Array der Wörter zurückgegeben.
Beispiel für die Anwendung von zerlege:
more SchillerBriefe3.txt
Sie haben durch den schönen Beitrag, den Sie in Ihrem _Dante_ zu den
Horen gegeben, ein zu entschiedenes Verdienst um den glücklichen
Fortgang dieses Journals, als dass ich Ihnen nicht den verbindlichsten
Dank dafür sagen sollte. Ich thue dieß um so lieber, da es mich zugleich
python3 zerlege.py SchillerBriefe3.txt
['Sie', 'haben', 'durch', 'den', 'schönen', 'Beitrag', 'den', 'Sie', 'in', 'Ihrem',
'Dante', 'zu', 'den', 'Horen', 'gegeben', 'ein', 'zu', 'entschiedenes',
'Verdienst', 'um', 'den', 'glücklichen', 'Fortgang', 'dieses', 'Journals', ... ]
2.5.15
API für
str.replace(wort,alt,neu)
wort, alt und neu sind vom Typ string.
Es wird der String zurückgegeben, der entsteht,
wenn man in wort jedes Vorkommen von alt durch neu ersetzt.
Beispiel:
str.replace("Hallo. Wie gehts? Gut.", ".", "!")
liefert 'Hallo! Wie gehts? Gut!'
str.replace("Teilnehmer: Anna, Bert, Chris", "Bert", "Peter")
liefert 'Teilnehmer: Anna, Peter, Chris'
In Python2 ist replace() nicht im Modul str, sondern im Modul string.
API für
str.split(wort,trenner)
wort und trenner sind vom Typ string.
Es wird ein Array zurückgegeben, dessen Einträge die Teile von wort,
vor denen und hinter denen trenner steht.
Beispiel:
str.split(' abc de f gg \n',' ') liefert
['', '', 'abc', '', 'de', 'f', 'gg', '\n']
2.5.17
#-------------------------------------------------------# zerlege.py
#-------------------------------------------------------import einlesen
def woerterliste(text):
# Ersetze alle Satzendezeichen durch " ."
for zeichen in "?!.":
text = str.replace(text,zeichen," .")
# Ersetze störende Zeichen durch " ".
for zeichen in '''"',;:-)([]<>*#_\n\t\r''':
text = str.replace(text,zeichen," ")
# Zerlege den Text in Wörter.
woerter = str.split(text,' ')
# Entferne "leere Wörter".
ergebnis = []
for i in range(len(woerter)):
if len(woerter[i])>=1: ergebnis += [woerter[i]]
return ergebnis
#----------------------------------------------------------def test():
text = einlesen.liesAlles("SchillerBriefe.txt")
stdio.writeln(woerterliste(text))
#----------------------------------------------------------if __name__ == '__main__': test()
2.5.18
Dictionaries
Ein Dictionary ist eine Liste aus Paaren ’key’:’value’.
Der value kann über den key angesprochen werden.
# woerterbuch.py
# Erzeuge ein leeres Dictionary.
woerterbuch = {}
# Trage Wortpaare ein.
woerterbuch['Aal'] = 'eal'
woerterbuch['Adler'] = 'eagle'
woerterbuch['Buch'] = 'book'
print woerterbuch
for i in woerterbuch:
print i, woerterbuch[i]
#----------------------------------------------------------------------------------# python woerterbuch.py
# {'Aal': 'eal', 'Buch': 'book', 'Adler': 'eagle'}
# Aal eal
# Buch book
# Adler eagle
2.5.19
Erzeugen eines Dictionaries mit
aufeinanderfolgenden Wörtern eines Textes
Die Aufbereitung des Textes wird abgeschlossen
mit der Erstellung eines Dictionaries, in dem zu jedem Wort x des Textes
ein Array aller Wörter steht, die im Text auf x folgen.
Der Dictionary-Eintrag
’heute’ : [’ist’, ’wird’, ’ist’, ’ein’, ’mal’, ’.’]
steht dafür, dass im Text auf das Wort heute zweimal das Wort ist und
jeweils einmal das Wort wird, ein bzw. mal und einmal das
Satzendezeichen . folgt.
#-------------------------------------------------------# wortpaare.py
#-------------------------------------------------------import sys, zerlege, einlesen
def konkordanz(woerterliste):
wortfolgen = {}
for i in range(len(woerterliste)-1):
if not woerterliste[i] in wortfolgen:
wortfolgen[woerterliste[i]] = []
wortfolgen[woerterliste[i]] += [woerterliste[i+1]]
return wortfolgen
def test():
text = einlesen.liesAlles(sys.argv[1])
woerterliste = zerlege.woerterliste(text)
liste = konkordanz(woerterliste)
print liste
if __name__ == '__main__': test()
Aus einem Text wird ein Dictionary erzeugt, das zu jedem Wort im Text einen String mit allen seinen direkten
Folgewörtern enthält.
2.5.21
Erzeugen eines Satzes wie im Text“
”
Schließlich können wir einen Satz erzeugen.
Wir beginnen mit einem Wort, das hinter einem .“ steht.
”
Anschließend wählen wir aus dem Dictionary wiederholt ein Folgewort
aus, bis wir wieder bei einem .“ ankommen.
”
2.5.22
# schreibe.py
import sys, stdio, zerlege, einlesen, wortpaare, random
def schreibe_einen_satz(k):
satzende = False
satz = ''
wort = "."
while not satzende:
wuerfelwurf = random.randrange(len(k[wort]))
wort = k[wort][wuerfelwurf]
if wort==".": satzende = True
else: satz = satz + ' ' + wort
return satz
def test():
text = einlesen.liesAlles(sys.argv[1])
woerterliste = zerlege.woerterliste(text)
liste = wortpaare.konkordanz(woerterliste)
stdio.writeln(schreibe_einen_satz(liste) + ".")
if __name__ == '__main__': test()
2.5.23
Zusammenfassung
Leider kommt hauptsächlich Unsinn heraus ...
python3 schreibe.py SchillerBriefe.txt
Erhalten Sie uns ruhig unterhalten.
python3 schreibe.py http://www.gutenberg.org/ebooks/24677.txt.utf-8
Noch nie erlebte ich den millionenmal stärkeren Mittagssonnenschein.
Aber wir haben etwas über den Umgang mit Strings gelernt.
Herunterladen