Seite 1 von 1
noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 14:01
von Horst-Olaf
Hallo zusammen,
Ich schreibe an einem Programm, das eine Textdatei einliest und die einzelnen Wörter zählt. Da habe ich jetzt folgendermaßen angefangen:
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
from pylab import *
with open ('bsp.txt', "r") as myfile:
data = myfile.readlines()
def analyse(data):
abc = "abcdefghijklmnopqrstuvwxyzöäüß"
wordlist = []
word = ""
signs = ".,?!_-;:)(<>"
for line in data:
for character in line:
characters = character.lower()
if characters in abc:
word += characters
else:
if len(word) >0:
wordlist.append(word)
if letters in signs:
wordlist.append(characters)
word = ""
return wordlist
Nach Erstellung einer Statistik über Worthäufigkeiten, werden Wörter mit Umlauten dort getrennt, wo eigentlich der Umlaut hingehört.
Es hat ja eine Umstrukturierung von Python 2 zu Python 3 gegeben, so dass Decoding eigentlich nicht mehr nötig ist (wenn ich das richtig verstanden habe).
Nun scheint Python den eingegebenen Text als UTF-8 zu interpretieren - wie kann ich ihm das abgewöhnen? Bzw. an welcher Stelle muss ich zu ISO8859-1 und wieder zurück wechseln?
Das ist wahrscheinlich eine typische Anfängerfrage, aber ich sitze seit gestern an dem Problem und google wild herum ohne an eine Lösung zu kommen.
Lieben Gruß
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 14:37
von Sirius3
Benutzt Du jetzt Python2 oder Python3. Die shebang-Zeile sagt Python2. Das würde auch erklären, warum das mit den Umlauten nicht funktioniert, denn Du verarbeitest Binar-Daten in ISO8859-1-Kodierung mit UTF8-Codierten Buchstabenbytes.
In Python3 mußt Du beim öffnen der Datei das richtige Encoding angeben.
Das `def analyse` steht bei Dir ziemlich unmotiviert mitten im Code. Warum ist `characters` ein Kleinbuchstabe? Was soll das `s` am Ende sagen? `letters` wird nirgends definiert.
Das ganze Aufspalten geht mit regulären Ausdrücken deutlich einfacher (mit Python3):
Code: Alles auswählen
with open('bsp.txt', encoding='ISO8859-1') as text:
wordlist = re.findall('[a-zäöüß]+|[-.,?!_;:)(<>]+', text.read().lower())
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 14:43
von __deets__
Welcher Text genau hat denn latin1 als Encoding? Der Quellcode? Das waere ungewoehnlich, da solltest du dir das "coding: ..." Geraffel sparen, und den als UTF-8 speichern und laden. Das ist seit Python3 der angenommene Default, und die beste Option.
Oder geht es dir um bsp.txt? Dazu gibt es den neuen Parameter encoding an die open-Funktion.
Code: Alles auswählen
with open('bsp.txt', 'r', encoding='latin1') as inf:
...
Dinge wie abc und signs sollten natuerlich Konstanten sein, also gross geschrieben, und auf Modul-Ebene. Wenn du
schreibst, wird der Code etwas kompakter, weil du dann nicht jedes Zeichen extra speichern musst.
Last but not least bietet sich fuer deinen Fall wahrscheinlich das re-Modul an, insbesondere re.split.
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 15:21
von Horst-Olaf
Danke für die schnellen Antworten:)
Ich benutze Python 3, ich wusste nicht, ob ich den Coding-Cookie am Anfang trotzdem brauche. Aber gut, dann nehm ich den raus.
Hmjaa, das ist leider kein eleganter Code...

Die Funktion ist eigentlich nicht eingerückt, "characters" sind alle Zeichen, die in einem Text vorkommen und mit "letters" meinte ich "characters".
Nun habe ich den Code
Code: Alles auswählen
with open('bsp.txt', 'r', encoding='latin1') as inf:
wordlist = re.findall('[a-zäöüß]+|[-.,?!_;:)(<>]+', inf.read().lower())
eingefügt und dafür die Umlaute aus dem ABC entfernt.
Nun läuft das Programm auch durch, aber es ändert nichts im Ergebnis. Die Wörter werden immernoch auf die selbe Weise getrennt.
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 15:41
von __deets__
Kannst du ggf. mal eine Beispieltext posten, den man benutzen kann? Und wie du dir das Ergebnis wuenschst? Mir ist das noch nicht klar geworden.
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 16:13
von snafu
Statt
lower() kann man auch einfach
re.IGNORECASE als Flag mitgeben. Dann bleiben die Wörter in ihrer Originalschreibweise erhalten.
Sähe dann so aus:
Code: Alles auswählen
import re
with open('bsp.txt', 'r', encoding='latin1') as inf:
words = re.findall('[a-zäöüß]+|[-.,?!_;:)(<>]+', inf.read(), re.IGNORECASE)
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 18:17
von Horst-Olaf
Das Programm ist Teil eines größeren Projekts.
Insgesamt soll ein Zufallsgenerator anhand der Worthäufigkeiten einen Zufallstext erstellen. Dabei ist die Idee, dass jeder beliebige Text eingespeist werden kann und dann im Stil dieses Texts ein neuer Text entsteht - zumindest grob und irgendwie.
Man gibt also einen Beispieltext ein (zum Beispiel ein Gedicht) und lässt die Wörter als Einzelstrings ausgeben. Das macht ja das (etwas holprige) Programm, das ich oben gepostet habe. Dann wird eine Statistik erstellt:
Code: Alles auswählen
def statistics(wordlist):
occur = dict()
for n in range(len(wordlist)):
word = wordlist[n]
if word in occur:
occur[word]+= 1
else:
occur[word]= 1
return occur
und
gibt dann
Code: Alles auswählen
{'denk': 2,
'dir': 2,
'ein': 2,
'tr': 2,
'ffelschwein': 2,
',': 6,
'denks': 2,
'wieder': 2,
'weg': 1,
...
aus. Dass es die Satzzeichen als Wörter interpretiert, ist so gedacht. Aber es fehlen die Umlaute und die Wörter werden an unnützen Stellen voneinander getrennt.
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 18:27
von __blackjack__
@Horst-Olaf: Das `occur` (ist ein obskurer Name) würde man besser mit einem `collections.Counter` lösen. Wenn man das so löst wie Du das da machst, dann bitte nicht mit ``for n in range(len(wordlist)):``. Das ist in Python ein „anti pattern“, weil man direkt über die Elemente iterieren kann, ohne den unnötigen Umweg über einen Index: ``for word in wordlist:``. Wobei Grunddatentypen nichts in Namen zu suchen haben. Einfach nur `words` statt `wordlist`. Das einzige was die Funktion davon fordert ist iterierbar zu sein.
Bei der Eingabedatei die Du weiter oben `inf` genannt hast, habe ich sofort an `math.inf` gedacht. Ist also auch kein guter Name. Keine kryptischen Abkürzungen.
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 18:37
von Sirius3
@Horst-Olaf: das Problem kann ich nicht nachvollziehen, sollte die Eingabedatei das richtige Encoding haben. Also hast Du da noch ein Problem.
Code: Alles auswählen
def statistics(wordlist):
result = dict()
for word in wordlist:
result[word] = result.get(word, 0) + 1
return result
oder kurz
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 18:50
von __deets__
@__blackjack__ das inf ist von mir, und fuer mich heisst das input-file. Das hat der TE sich also nicht ausgedacht. Und Kontext matters.
@Horst-Olaf: fuer ein solches Vorhaben eignen sich neuronale Netze denke ich besser. Die erreichen erstaunlich realistische nonsense-Texte. Oder hidden markov chains wenn ich mich recht erinnere.
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 19:37
von __blackjack__
Für mich heist das erst einmal gar nichts, aber `inf` aus `math` kenne ich halt. Ausserhalb ist das eine kryptische Abkürzung für mich.
Re: noch eine encoding-Frage
Verfasst: Mittwoch 27. Februar 2019, 20:04
von snafu
Da die Einführung und Verwendung von inf direkt hintereinander erfolgen, sollte man auch mit der Abkürzung zurecht kommen. Schwieriger fände ich es, wenn 10 Zeilen dazwischenliegen. So oder so täte es aber nicht weh, das inf einfach als infile oder input_file auszuschreiben.
Re: noch eine encoding-Frage
Verfasst: Donnerstag 28. Februar 2019, 10:13
von Horst-Olaf
Hui, da bin ich euch schonmal sehr dankbar. Ich habe jetzt alles nochmal über den Haufen geworfen und euren Ratschlägen folgend überarbeitet. Das ist jetzt nur noch in Drittel des Codes, wie schön. Die Wörter werden mit dem split-Operator nicht mehr getrennt, die Umlaute sind aber immernoch im Weg. Ich habe jetzt beschlossen, sie einfach zu ersetzen. Das funktioniert aber nicht, indem ich "ü" durch "ue" ersetze, sondern nur mit:
Code: Alles auswählen
with open('bsp.txt', 'r') as myfile:
wordlist = myfile.read().replace("ü","ue").split()
Gibt es da eine elegantere Lösung? Nach dem "split()" ist ja eine Liste erstellt worden. Kann ich dann überhaupt noch Elemente innerhalb eines Strings ersetzen?
Re: noch eine encoding-Frage
Verfasst: Donnerstag 28. Februar 2019, 10:28
von __blackjack__
@Horst-Olaf: Die Lösung ist beim öffnen der Datei die Kodierung anzugeben, nur dann können die Bytes aus der Datei korrekt zu Zeichen dekodiert werden. Und dann ist ein ü auch ein ü. Und man muss das dann auch nicht ersetzen, denn dann funktionieren auch die regulären Ausdrücke mit Umlauten.
Re: noch eine encoding-Frage
Verfasst: Donnerstag 28. Februar 2019, 10:42
von Sirius3
@Horst-Olaf: dann war Deine Vermutung, dass es sich bei der Datei um eine ISO8859-1 kodierte handelt, offensichtlich falsch, und Du mußt nur das richtige Encoding angeben:
Code: Alles auswählen
with open('bsp.txt', 'r', encoding='utf-8') as input_file:
words = re.findall('[a-zäöüß]+|[-.,?!_;:)(<>]+', input_file.read(), re.IGNORECASE)