Seite 1 von 2

Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 08:44
von mutetella
Guten morgen...

... es ist zum verrückt werden! Ich hatte das Problem schon einmal, finde die damalige Lösung aber weder in meinem Hirn noch hier über die Suche...

Code: Alles auswählen

In [35]: month = 'März'

In [36]: month
Out[36]: 'M\xc3\xa4rz'

In [37]: len(month)
Out[37]: 5
:? Ich verstehe gerade noch soviel, dass der Umlaut 'ä' aus irgendeinem Grund 2 'Stellen' belegt.

Wie bekomme ich den 4-stelligen 'März' in 'month' hinein?

Gruß
mutetella

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 08:54
von mkesper
Hilft das?

Code: Alles auswählen

Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> month = u'März'
>>> len(month)
4
>>>

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 08:57
von BlackJack
@mutetella: Das ist ein UTF-8 kodiertes 'ä'. Wenn Du mit Text arbeiten möchtest, solltest Du `unicode` verwenden. Allerdings ist auch dort nicht sichergestellt, dass ein Buchstabe nur einen Index in der Zeichenkette umfasst.

Code: Alles auswählen

In [181]: m = 'März'.decode('utf-8')

In [182]: m
Out[182]: u'M\xe4rz'

In [183]: len(m)
Out[183]: 4

In [184]: unicodedata.normalize('NFD', m)
Out[184]: u'Ma\u0308rz'

In [185]: len(unicodedata.normalize('NFD', m))
Out[185]: 5

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 10:10
von mutetella
Wow... das artet ja in Arbeit aus... :wink:

Ich gehe also wie folgt vor:
  1. Ich lese aus einer UTF-8 codierten config-Datei diverse Strings (darunter eben auch der 'März') ein
  2. Diese Strings wandle ich zur internen Verarbeitung mit str.decode('utf8') in unicode um
  3. Jedes mal, bevor ich einen dieser unicode-Strings auf dem Bildschirm ausgebe (oder mit str.format() verwende), codiere ich ihn mit str.encode('utf8') wieder um.
Ist das so richtig?

mutetella

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 10:48
von BlackJack
@mutetella: Zu 3.: Wieso bei `str.format()`?

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 11:09
von mutetella
@BlackJack:
Das habe ich mich auch gefragt.

Code: Alles auswählen

In [143]: '{0}'.format('März')
Out[143]: 'M\xc3\xa4rz'

In [144]: '{0}'.format(u'März')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)

/home/claus/Daten/Python/iPython/<ipython console> in <module>()

UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-2: ordinal not in range(128)
:K

mutetella

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 11:15
von Hyperion
mutetella hat geschrieben:@BlackJack:
Das habe ich mich auch gefragt.

Code: Alles auswählen

In [143]: '{0}'.format('März')
Out[143]: 'M\xc3\xa4rz'

In [144]: '{0}'.format(u'März')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)

/home/claus/Daten/Python/iPython/<ipython console> in <module>()

UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-2: ordinal not in range(128)
:K

mutetella
Ist doch ganz klar: Bei 143 sind beides Bytestrings, die in der Kodierung der Python-Shell vorliegen. Diese kann offensichtlich mit Umlauten umgehen - die __repr__-Darstellung kommt da ja nur mangels Ausgabe.

Bei 144 ist die Sache anders: Du willst in einen Bytestring einen Unicodestring einfügen. Das impliziert eine Konvertierung. Python wandelt also den Unicodestring in einen Bytestring um. Das Default-encoding ist da eben ASCII; das umfasst aber ja nun mal keine Umlaute und daher krachts.

Probier das Bsp. aus 144 mal ohne das "ä" und lass Dir den typen des Ergebnisses anzeigen.

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 11:16
von /me
mutetella hat geschrieben:

Code: Alles auswählen

In [144]: '{0}'.format(u'März')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)

/home/claus/Daten/Python/iPython/<ipython console> in <module>()

UnicodeEncodeError: 'ascii' codec can't encode characters in position 1-2: ordinal not in range(128)
Schnarchsack!

Code: Alles auswählen

'{0}'.format(u'März')
Ich verwende in meinem aktuellen Python 2 Code ohnehin immer

Code: Alles auswählen

from __future__ import unicode_literals

Re: Umlaute und len()...

Verfasst: Dienstag 22. März 2011, 11:44
von BlackJack
@mutetella:

Code: Alles auswählen

In [201]: u'{0}'.format('März'.decode('utf-8'))
Out[201]: u'M\xe4rz'

Re: Umlaute und len()...

Verfasst: Freitag 25. März 2011, 15:08
von mutetella

Code: Alles auswählen

In [86]: template = '{0} {1}'.decode('utf-8')

In [87]: m = 'März'.decode('utf-8')

In [88]: y = '2011'.decode('utf-8')

In [89]: len(template.format(m, y))
Out[89]: 9

In [90]: template = u'{0} {1}'

In [91]: m = u'März'

In [92]: y = u'2011'

In [93]: len(template.format(m, y))
Out[93]: 10
Warum?

Re: Umlaute und len()...

Verfasst: Freitag 25. März 2011, 15:21
von b.esser-wisser
Warum?
Weil Unicode-literale in Ipython nicht richtig funktionieren:

Code: Alles auswählen

# Windows XP:
# Falsch
In [1]: u"März"
Out[1]: u'M\x84rz'
# richtig:
In [2]: "März".decode('cp850')
Out[2]: u'M\xe4rz'#
Man kann sowas wie "u=lambda s: s.decode(...)" als Würg-around benutzen.

Re: Umlaute und len()...

Verfasst: Freitag 25. März 2011, 15:32
von Hyperion
mutetella hat geschrieben: Warum?
Warum nach > 300 Postings keine Python-Code-Tags? :twisted:

Re: Umlaute und len()...

Verfasst: Freitag 25. März 2011, 15:36
von /me
mutetella hat geschrieben:

Code: Alles auswählen

In [87]: m = 'März'.decode('utf-8')
Was soll das denn für ein Konstrukt sein und warum geht das? 'März' ist doch gar keine gültige UTF-8-Codierung. Verstanden hätte ich ja

Code: Alles auswählen

m = 'März'.decode('iso-8859-15')
mutetella hat geschrieben:

Code: Alles auswählen

In [90]: template = u'{0} {1}'

In [91]: m = u'März'

In [92]: y = u'2011'

In [93]: len(template.format(m, y))
Out[93]: 10
In IDLE sieht es bei mir wie folgt aus:

Code: Alles auswählen

>>> template = u'{0} {1}'
>>> m = u'März'
>>> y = u'2011'
>>> len(template.format(m, y))
9

Re: Umlaute und len()...

Verfasst: Freitag 25. März 2011, 15:57
von DasIch
/me hat geschrieben:
mutetella hat geschrieben:

Code: Alles auswählen

In [87]: m = 'März'.decode('utf-8')
Was soll das denn für ein Konstrukt sein und warum geht das? 'März' ist doch gar keine gültige UTF-8-Codierung.
Das ist ein workaround weil das Terminal hier noch Nebeneffekte verursacht.

Am besten probiert man sowas erst gar nicht in einer Shell aus.

Re: Umlaute und len()...

Verfasst: Freitag 25. März 2011, 16:12
von mutetella
besser.wisser hat geschrieben:Weil Unicode-literale in Ipython nicht richtig funktionieren:
Ok, in der Pythonshell stimmt's dann auch:

Code: Alles auswählen

>>> template = u'{0} {1}'
>>> m = u'März'
>>> y = u'2011'
>>> len(template.format(m, y))
9