Umlaute

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.
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Hallo liebe Mitglieder,

weiss jemand, was man wie / wo ändern muss, damit python Statements à la:

Code: Alles auswählen

re.sub("ß", "ss", string)
versteht?
Das Problem liegt ja darin, dass nicht-ASCII-Zeichen per default nicht "erkannt" werden...

Danke im Voraus.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nein, das Problem liegt darin, dass "ß" ein _Bytestring_ ist. `string` also dasselbe Encoding haben muss wie deine Datei damit der Code funktioniert.

Code: Alles auswählen

In [4]: print re.sub('ß', 'ss', u'Straße')
Straße

In [5]: print re.sub(u'ß', 'ss', u'Straße')
Strasse

In [6]: print re.sub(u'ß', 'ss', 'Straße')
Straße

In [7]: print re.sub('ß', 'ss', 'Straße')
Strasse
BlackJack

@MarcelF6: Du bekommst da doch ziemlich sicher eine Ausnahme. Wie lautet die denn? Komplett bitte. Hast Du den Text gelesen? Also auch dem Hinweis nachgegangen?
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Ja, die Fehlermeldung besagt dass kein encoding definiert wurde. Also:
" [...]on line 17, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details "

Also es geht um folgenden Programmausschnitt:

Code: Alles auswählen

f = file(unicodeObjekt)
    while True:
        out = f.readlines()
        out = out.lower()
        ae = re.sub(u'ä', 'ae', out)
        oe = re.sub(u"ö", "oe", ae)
        ue = re.sub(u"ü", "ue", oe)
        ss = re.sub(u"ß", "ss", ue)
        return ss
    f.close()
So "einfach" wie ich gedacht habe funktioniert das leider nicht. Also gibt es eine andere Möglichkeit das so zu machen wie ich es vor hatte?
lunar

@MarcelF6: Lies für den Anfang doch einfach mal die Seite, auf welche in der Fehlermeldung verwiesen wird.
BlackJack

@MarcelF6: `re.sub()` ist hier auch etwas mit Kanonen auf Spatzen geschossen. Wenn Du einfach nur statische Zeichenfolgen ersetzen willst, dann gibt es auf Zeichenketten dafür eine einfachere Methode.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Mich würde nun aber wirklich stark interessieren, aus welchem Grund du überall diese unnötigen ``while True`` verwendest.
Das Leben ist wie ein Tennisball.
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Habe ich gemacht - so wie ich es verstanden habe muss man gewisse encodings vornehmen.
Ich habs mal probiert:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-#

import re
import sys

def funktion(unicodeObjekt):
    '''Gib eine Datei auf der Standardausgabe aus.'''
    f = unicode(file(unicodeObjekt))
    f.unicode.encode('utf-8')
    while True:
        out = f.readlines()
        out = out.lower()
        ae = re.sub(u'ä', 'ae', out)
        oe = re.sub(u"ö", "oe", ae)
        ue = re.sub(u"ü", "ue", oe)
        ss = re.sub(u"ß", "ss", ue)
        return ss
    f.close()

if len(sys.argv) < 2:
    print 'Es wurden keine Parameter übergeben.'
    sys.exit()
else:
    for unicodeObjekt in sys.argv[1:]:
        funktion(unicodeObjekt)
Wie gesagt: "probiert". Das Problem ist, dass ich aus der Beschreibung nicht ganz schlau wurde, was genau wie encodiert werden sollte..

@Blackjack: Ich habe als input einfach ein Unicode-Objekt.

@EyDu: Werd ich noch wegmachen ;) ..hab das eben alles nacheinander geschrieben :)
Zuletzt geändert von MarcelF6 am Sonntag 18. März 2012, 02:59, insgesamt 1-mal geändert.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

- „while True“ ist sinnlos: Du verlässt die Schleife eh im ersten Durchgang.
- Du brauchst immer noch kein re.sub für einfache Substitutionen. „str.replace“ reicht vollkommen.
- „f.close()“ wird nie ausgeführt werden, da du vorher schon die Funktion verlässt.
- Wenn du kein Emacs verwendest kannst du auch „# coding: utf-8“ benutzen.
- Du probierst viel zu wild ‘rum!

Code: Alles auswählen

In [8]: unicode(file('blabla.txt'))
Out[8]: u"<open file 'blabla.txt', mode 'r' at 0x956e5a0>"

In [9]: _.unicode.encode('utf-8') # _ ist u"<open ...>"
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/home/jakob/<ipython-input-9-3480aff0e5da> in <module>()
----> 1 _.unicode # _ ist u"<open ...>"

AttributeError: 'unicode' object has no attribute 'unicode'
Schau dir mal die Seiten aus Hyperions Signatur an, ich finde, dass Unicode und Encodings in Python da sehr gut erläutert werden:
Leonidas’ FolienVon Umlauten, Unicode und Encodings im Wiki — Pragmatic Unicode – Präsentation von Ned Batchelder zu Unicode
Zuletzt geändert von nomnom am Samstag 17. März 2012, 22:49, insgesamt 1-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Wie wäre es, wenn du uns auch das Beispiel gibst, mit dem du arbeitest? Ganz offensichtlich existiert die Funktion "normalize" nicht, wahrscheinlich ist "funktion" gemeint.

Folgender Code sieht auf jeden Fall falsch aus:

Code: Alles auswählen

f = unicode(file(unicodeObjekt))
f.unicode.encode('utf-8')
Zerlege das mal in einzelne Schritte und lasse dir die Zwischenergebnisse ausgeben. Den Trick solltest du jetzt ja eignetlich schon kennen.

Zum ``while-True``: Warum entfernst du es nicht bevor du es postest? Um so weniger Code wir lesen müssen, desto wahrscheinlicher ist es, dass dir geholfen wird. Vorallem wenn es um Abschnitte geht, auf die man die bereits hingeweisen hat.
Das Leben ist wie ein Tennisball.
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Danke für die Hilfe.
Also ich hab den Code auch nochmals überarbeitet:

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: utf-8 -*-#

import sys

def funktion(unicodeObjekt):
    '''Gib eine Datei auf der Standardausgabe aus.'''
    with open(unicodeObjekt, "r") as f:
	content = unicode(f.read())
	return string.replace(content, 'ä', 'ae')


if len(sys.argv) < 2:
    print 'Es wurden keine Parameter übergeben.'
    sys.exit()
else:
    funktion(sys.argv[1])
Allerdings hab ich immernoch eine Fehlermeldung:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 8: ordinal not in range(128)
Ich bin mir aber nicht sicher, ob das wirklich ein Problem wegen des Codes ist oder ob die Meldung vom Editor stammt. Denn jetzt reklamiert die shell auch bei normalen print-Statements mit ä,ö,ü dass sie keine ASCII-Characters seien. Woran genau liegt das Problem?
Dankeschön!
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Wenn du ein „unicode“-Objekt erstellen möchtest und kein Encoding angibst, dann wird angenommen, dass ASCII verwendet wurde.

Code: Alles auswählen

    content = unicode(f.read())
Du musst wissen, in welchem Encoding deine Datei vorliegt und dann

Code: Alles auswählen

f.read().encode('*encoding*')
aufrufen.

Code: Alles auswählen

    return content.replace(u'ä', u'ae') # ist übrigens "besser" als string.replace, vor allem wenn man string gar nicht importiert
BlackJack

@nomnom: Du meinst sicher `decode()` nach dem einlesen…

@MarcelF6: Die Kodierungsprobleme beim ``print`` könnten daran liegen, dass Du versuchst `unicode`-Objekte auszugeben ohne sie vorher in `str` zu konvertieren. Und zwar mit der Kodierung die das Programm erwartet, dass die Zeichen dann darstellen soll.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

BlackJack hat geschrieben:@nomnom: Du meinst sicher `decode()` nach dem einlesen…
Ja, meinte ich … :oops:
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Danke euch beiden für die Hilfe.
@nomnom: Hast du es so gemeint? :

Code: Alles auswählen

def funktion(unicodeObjekt):
    '''Gib eine Datei auf der Standardausgabe aus.'''
    with open(unicodeObjekt, "r") as f:
	content = unicode(f.read().decode('utf-8'))
	return content.replace(u'ä', u'ae')
BlackJack

@MarcelF6: Erkläre mal was in der Zeile in der `content` an einen Wert gebunden wird in jedem einzelnen Schritt passiert. Welchen Typ haben zum Beispiel die jeweiligen Zwischenergebnisse und was machen die einzelnen Aufrufe? Da sollte Dir dann etwas auffallen.

Des weiteren ist der Funktionsname, der Name des Arguments, und der Docstring falsch, weil keines davon tatsächlich die Bedeutung korrekt wiedergibt. Also `funktion()` streng genommen schon, aber das ist an der Stelle doch ein wenig *zu* generisch um nützlich zu sein.
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Jetzt habe ich es so:

Code: Alles auswählen

deffunktion(unicodeObjekt):
    '''Gib eine Datei auf der Standardausgabe aus.'''
    with open(unicodeObjekt, "r") as f:
	content = (f.read().decode('utf-8'))
	print content.replace(u'ä', u'ae')
(Um die Namen kümmere ich mich dann nachher ;) )
Also, bei der ersten Erwähnung von content wird der Dateiinhalt gelesen und nach UTF-8 dekodiert. [zum Testen habe ich in der Datei einige ä,ö,ü]
Das müsste eigentlich iO sein, denn mit print-Statements erhalte ich auch den korrekt-dargestellten Dateiinhalt.
Dann aber reklamiert meine shell schon wieder:
SyntaxError: Non-ASCII character '\xc3' in file 22.py on line 16, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details
Das merkwürdige ist: Auch wenn ich Kommentare mit ä,ö,ü mache, kommt nun diese Fehlermeldung. Wieso? Ich habe doch das UTF-8-Format - da sollte dies kein Problem sein...
BlackJack

@MarcelF6: Es wird nicht *nach* UTF-8 dekodiert, sondern *von*.

Du hast Bytewerte ausserhalb von ASCII in Deiner Quelltextdatei, dann musst Du dem Compiler über den Kommentar mitteilen in welcher Kodierung die sind. Das hat nichts damit zu tun ob von dem Code in dem Skript Dateien geladen werden und in welcher Kodierung *die* vorliegen.
MarcelF6
User
Beiträge: 226
Registriert: Samstag 3. März 2012, 21:30

Und das mache ich so, oder:
# -*- coding: utf-8 -*-#

Also Code gesamthaft:

Code: Alles auswählen

# -*- coding: utf-8 -*-#

import sys

def funktion(unicodeObjekt):
    '''Gib eine Datei auf der Standardausgabe aus.'''
    with open(unicodeObjekt, "r") as f:
	content = (f.read().decode('utf-8'))
	print content.replace(u'ä', u'ae')
	
if len(sys.argv) < 2:
    print 'Es wurden keine Parameter uebergeben.'
    sys.exit()
else:
    funktion(sys.argv[1])
Also eigentlich kann ich die Antwort so schon geben: Nein, so klappt es nicht. Obwohl ich gelesen habe, dass es so klappen müsste.
BlackJack

@MarcelF6: Da ist jetzt wieder die Frage was „klappt nicht” konkret bedeutet. Die Ausnahme das der Quelltext Zeichen ausserhalb ASCII enthält ohne das eine Kodierung angegeben ist, sollte zumindest nicht mehr kommen.

Was jetzt noch passieren kann, was ich aber auch schon erwähnt habe, ist das nicht erraten werden kann was der Prozess am anderen Ende der Standardausgabe für eine Kodierung erwartet. Dann wird dafür ASCII angenommen und das geht natürlich nicht wenn in dem `unicode`-Objekt, welches ausgegeben werden soll, etwas ausserhalb von ASCII enthalten sein sollte.
Antworten