Einfache Datei mit Umlauten einlesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Hallo zusammen,

ich möchte einfach eine Datei einlesen und am Bildschirm ausgeben.

Inhalt der Datei (infile):
*************
Österreich
*************

Das Programm hierzu:

Code: Alles auswählen

#! /opt/python3.1/bin/python3
# -*- coding: iso-8859-15 -*-

##################################################################################################
import os
import sys
import codecs
import locale

infile = /tmp/umlaut.txt"

FileEncoding = locale.getpreferredencoding()
print ("Locale: %s" % FileEncoding)

IN_File = codecs.open(infile, 'r', FileEncoding).readlines()

print (IN_File)
Wenn in der Datei keine Umlaute vorkommen, funktioniert es auch...

Habt ihr einen Vorschlag?

CU,
Api
deets

Wie waers denn mit dem encoding des Files, statt einem preferred encodings deines Systems? Und bevor du fragst: nein, das kann Python nicht selbst bestimmen, man muss generell (es gibt wenige Ausnahmen wie XML) immer wissen, in welchem Encoding ein File gespeichert wurde.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Was meinst du denn genau mit einem "encoding" der Datei?

Dieses funktioniert leider nicht... Kannst du mir sagen, wie das sein muss?

Code: Alles auswählen

#! /opt/python3.1/bin/python3
# -*- coding: iso-8859-15 -*-

##################################################################################################
import os
import sys
import codecs
import locale

infile = /tmp/umlaut.txt"

FileEncoding = locale.getpreferredencoding()
print ("Locale: %s" % FileEncoding)

IN_File = open(infile, 'r').readlines()
IN_File = IN_File.encode('iso-8859-15')

print (IN_File)


Traceback (most recent call last):
File "umlaut", line 18, in <module>
IN_File = IN_File.encode('iso-8859-15')
AttributeError: 'list' object has no attribute 'encode'
deets

Du hast doch in deinem originalen Code eine Variable "FileEncoding". Und die musst du auf das encoding des files setzen.

Dein zweites Snippet ist voelliger Quatsch, weil du da eine Datei einliest als Liste von Zeilen, und die dann dekodieren willst, als ob's ein String waere. Das geht natuerlich nicht.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Wie finde ich denn heraus, welches Encoding mein File hat?
deets

*seufz*

Das habe ich doch schon im ersten Post geschrieben - das weiss niemand, ausser dir. Bzw. demjenigen, der die Datei geschrieben hat. Man kann ein bisschen raten, aber eine Garantie gibt es nicht. Darum solltest du das schon selbst wissen.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

Nun ja, ich weiss nu nicht so recht, was ich da machen soll... :-((

Ich befinde mich hier unter UNIX, habe die Datei selbst verfasst und dann abgespeichert.

Unter Coding verstehe ich eigentlich, dass ich diese Datei wohl als ""iso-8859-1" oder halt ""iso-8859-15" angelegt habe. Oder ist das schon falsch?

Aber ein
FileEncoding = "iso-8859-1"
funktioniert eben auch nicht - wahrscheinlich, weil etwas grundsätzliches falsch ist!?
JonasR
User
Beiträge: 251
Registriert: Mittwoch 12. Mai 2010, 13:59

Unter linux kannst du

Code: Alles auswählen

file DATEINAME
eingeben und schon hast du das encoding.
Funktioniert zumindest bei mit mit vi erstellten Datein ;)

Code: Alles auswählen

xxx:~# file test.txt
test.txt: ISO-8859 text
deets

@api

Ob iso-8859-1 richtig oder falsch ist musst du schon selbst wissen. Wenn es denn alle Umlaute & Sonderzeichen abbilden kann, die dich interessieren, dann reicht es schon.

Und leider ist deine Fehlerbeschreibung von 'es geht nicht' aeusserst duerftig. Mit einem byte-encoding wie latin1 (anderer Name fuer iso-8859-1) bist du an sich naemlich in einer Situation, so ziemlich *alles* einlesen zu koenne. Kommt Gruetze bei rum, aber keine Exception zB.

Insofern: was genau machst du, und was schlaegt fehl?

Edit: hier mal ein kleiner test, der das veranschaulicht, das latin1 immer geht:

Code: Alles auswählen

l = []

for i in xrange(256):
    l.append(chr(i))

s = "".join(l)

u = s.decode("latin1") # geht immer
print u.encode("utf-8") # mein terminal hat utf-8
u = s.decode("utf-8") # geht nicht
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@deets

Mein Programm sieht zur Zeit so aus:

Code: Alles auswählen

#! /opt/python3.1/bin/python3
# -*- coding: ascii -*-

##################################################################################################
import os
import sys
import codecs
import locale

infile = "/tmp/umlaut.txt"

FileEncoding = "latin1"

IN_File = codecs.open(infile, 'r', FileEncoding).readlines()

print (IN_File)
Und die Fehlermeldung lautet:
File "umlaut", line 20, in <module>
print (IN_File)
UnicodeEncodeError: 'ascii' codec can't encode character '\xd6' in position 21: ordinal not in range(128)
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@JonasR

Ich befinde mich leider zur Zeit nicht unter Linux - sondern unter UNIX. Somit ergibt die Anweisung
file umlaut.txt
umlaut.txt: data
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@deets

Noch mal als Hinweis am Rande. Ich benutze Python 3.1 ! (siehe 1. Zeile)

Unter Python 2.4.6 habe ich dieses Problem nicht... Da funktioniert das.
deets

Siehste, und schon wird es klarer, wenn du genug Infos gibst: dein Problem ist mitnichten das *einlesen* der Datei, sondern die Ausgabe ihres Inhaltes. Und so, wie ich das in meinem Snippet gemacht habe, musst du das auch machen - naemlich den unicode-string von Python vor der Ausgabe zu einem byte-string in einem encoding wandeln, das dein Terminal versteht. Welches das ist, kannst auch wieder nur du wissen, meines ist wie gesagt utf-8.
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@deets

Ja - super! Jetzts läufts auch wie gewünscht...

Code: Alles auswählen

#! /opt/python3.1/bin/python3
# -*- coding: ascii -*-

##################################################################################################
### -*- coding: iso-8859-15 -*-
##################################################################################################
import os
import sys
import codecs
import locale

infile = "/tmp/umlaut.txt"

FileEncoding = "ISO-8859-15"

IN_File = codecs.open(infile, 'r', FileEncoding).readlines()

for line in IN_File:
  print (line.encode(FileEncoding))
So werden genau die Zeilen dargestellt, die auch in der Datei stehen.

Du hast mir wirklich weitergeholfen. Danke dir :D
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

api hat geschrieben:Ich befinde mich leider zur Zeit nicht unter Linux - sondern unter UNIX. Somit ergibt die Anweisung
file umlaut.txt
umlaut.txt: data
$man file hat geschrieben:Any file that cannot be identified as having been written in any of the character sets listed above is simply said to be ‘data’.
Alles klar? Das hat was mit 'file' und Deiner Datei, aber nicht mit Deinem OS flavour zu tun.

Im Übrigen ist ein Konstrukt wie

Code: Alles auswählen

infile = open(...).readlines()
for line in infile: pass
infile.close()
# anstelle von
infile = open(...)
for line in infile: pass
infile.close()
# oder
with open(...) as infile:
    for line in infile: pass
sehr unschön (Speicherverbrauch, Speed, Redundanz).

HTH
Christian

PS Mal abgesehen davon, daß Listen keine close()-Methode haben :oops: ('infile' wäre im ersten Teil eine Liste, kein Fileobjekt, wie Du vielleicht vermutet hast, api.)
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@CM

Danke für den Hinweis. Habe das Script dann mal so angepasst:

Code: Alles auswählen

#! /opt/python3.1/bin/python3
# -*- coding: ascii -*-

##################################################################################################
### -*- coding: iso-8859-15 -*-
##################################################################################################
import os
import sys
import codecs
import locale

infile = "/tmp/umlaut.txt"

FileEncoding = "ISO-8859-15"

with codecs.open(infile, 'r', FileEncoding) as f:
  for line in f:
    print (line.encode(FileEncoding))
Muss ich denn jetzt bei diesem Kontrukt am Ende noch ein

Code: Alles auswählen

f.close()
einsetzen oder nicht?

Und dann noch zu deinem Statement...
Alles klar? Das hat was mit 'file' und Deiner Datei, aber nicht mit Deinem OS flavour zu tun.
Was meinst du damit? Ich habe schließlich eine ganz normale Datei (mit vi erzeugt).

CU,
Api
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

api hat geschrieben:Muss ich denn jetzt bei diesem Kontrukt am Ende noch ein

Code: Alles auswählen

f.close()
einsetzen oder nicht?
Nein, with kümmert sich drum.
api hat geschrieben:Was meinst du damit? Ich habe schließlich eine ganz normale Datei (mit vi erzeugt).
Das kann schon sein. Aber aus irgendeinem Grund erkennt file nicht mehr als 'data'. Das kann an vielen Dingen liegen, aber nicht daran, daß Du ein bestimmtes Unix-flavour nutzt. Vielleicht ist magic (worauf file zurückfällt) bei dem System irgendwie nicht so umfangreich?
api
User
Beiträge: 181
Registriert: Donnerstag 7. August 2008, 21:23

@CM

Also, wenn ich mit vi eine Datei erfasse (test.txt), mit folgendem Inhalt:
test:
Dann der test mit "file"
file test.txt
test.txt: ascii text
Wenn die Datei Umlaute enthält:
test:Ö
Dann der test mit "file"
file test.txt
test.txt: data
Das müsste doch bedeuten, dass das OS das nicht lesen kann, oder?
BlackJack

@api: Wie ja schon von deets geschrieben wurde, kann man die Kodierung einer Textdatei nicht automatisch ermitteln, sondern höchstens raten. Wenn nur Werte im (druckbaren) ASCII-Bereich vorkommen, vermutet ``file``, dass es sich wohl um ASCII handelt. Bei ``test:Ö`` ist (fast) unabhängig von der verwendeten Kodierung klar, dass es nicht ASCII ist. Also sagt Dein ``file`` es sind allgemein Daten. Das ist der Fallback, der nie falsch ist. Denn ganz allgemein enthält eine Datei immer Daten.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Nee, file sollte das Beispiel eindeutig als ein Unicode-flavour erkennen - auch wenn das encoding nicht im vimrc gesetzt ist. Der Algorithmus von file sieht vor systematisch durchzuraten und erst wenn gar nichts Näherliegendes erkannt wird, greift file auf 'data' zurück. Aber, api, ich würd' mich mal davon frei machen den Fehler beim OS zu suchen. Allenfalls, wenn Du an einer wirklich alten Maschine sitzt, könnte die mangelnde Wartbarkeit dazu führen, daß Deine 'file'-Version schlechter rät. Aber 'data'? - Das kommt mir immer noch komisch vor. (Auf VAX/VMS habe ich unabsichtlich immer wieder mal Zeichen erzeugt, die zum Teil gar nicht dargestellt wurden. Da war Debugging ein besonderer Spaß ;-) . Selbst da war das OS "unschuldig".)
Antworten