Wie Zeichensatz ermitteln?

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.
Antworten
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Zum testen, in welchen Format ein String vorliegt, hab ich mir das gebastelt:

Code: Alles auswählen

def codectest( txt ):
    codeclist = ['ascii', 'big5', 'big5hkscs', 'cp037', 'cp424', 'cp437', 'cp500',
        'cp737', 'cp775', 'cp850', 'cp852', 'cp855', 'cp856', 'cp857', 'cp860',
        'cp861', 'cp862', 'cp863', 'cp864', 'cp865', 'cp866', 'cp869', 'cp874',
        'cp875', 'cp932', 'cp949', 'cp950', 'cp1006', 'cp1026', 'cp1140', 'cp1250',
        'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', 'cp1257', 'cp1258',
        'euc_jp', 'euc_jis_2004', 'euc_jisx0213', 'euc_kr', 'gb2312', 'gbk', 'gb18030',
        'hz', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_2004',
        'iso2022_jp_3', 'iso2022_jp_ext', 'iso2022_kr', 'latin_1', 'iso8859_2',
        'iso8859_3', 'iso8859_4', 'iso8859_5', 'iso8859_6', 'iso8859_7', 'iso8859_8',
        'iso8859_9', 'iso8859_10', 'iso8859_13', 'iso8859_14', 'iso8859_15', 'johab',
        'koi8_r', 'koi8_u', 'mac_cyrillic', 'mac_greek', 'mac_iceland', 'mac_latin2',
        'mac_roman', 'mac_turkish', 'ptcp154', 'shift_jis', 'shift_jis_2004',
        'shift_jisx0213', 'utf_16', 'utf_16_be', 'utf_16_le', 'utf_7', 'utf_8',
        'base64_codec', 'bz2_codec', 'hex_codec', 'idna', 'mbcs', 'palmos',
        'punycode', 'quopri_codec', 'raw_unicode_escape', 'rot_13', 'string_escape',
        'undefined', 'unicode_escape', 'unicode_internal', 'uu_codec', 'zlib_codec'
    ]
    for c in codeclist:
        try:
            #~ print unicode( txt, c ), "-", c
            print "%s - %s" % (c, txt.encode(c) )
        except:
            pass


codectest( "test äöüß" )
Es scheint aber nicht so richtig zu funktionieren...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

Klar funktioniert das. Bei mir kommt jedenfalls keine Fehlermeldung.

Was erwartest Du denn?

Mal davon abgesehen, das Du ganz sicher 'decode()' meintest, kann man die Kodierung von Texten nicht wirklich zuverlässig automatisch ermitteln.

Woher soll ein Programm wissen, ob Du "test äöüß" in UTF-8 oder "test äöüà " in Latin-1 meintest? Als Bytefolge ist beides das gleiche.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Das ganze war ein Test für meine CRID-Datei-einlese-Ding http://python.sandtner.org/viewtopic.php?t=3011

Wenn ich einen String aus der Binärdatei ausgelesen hab, sind die Umlaute erstmal nicht zu sehen. Was ein bischen komisch ist, das nicht nur das Sonderzeichen, sondern auch Zeichen danach codiert sind.
Außerdem fangen die Strings hin und wieder mit dem Zeichen \x05 an. Was ich aber noch leicht mit einem .replace("\x05","") rausfiltern kann.

Ansonsten sehen die so aus:

Code: Alles auswählen

R�eliges & Co.: P�tlich zum Fr�ingsbeginn tritt Bl祥lbarde Otto wieder in Aktion. In einem Oster-TV-Special am 28. M峺 um 20.15 Uhr strahlt das WDR-Fernsehen die sch篳ten Sketche und Showauftritte des Ostfriesen aus.
string_escape:

Code: Alles auswählen

R\xed\xb4\xb3eliges & Co.: P\xed\xaf\xabtlich zum Fr\xed\xa9\xacingsbeginn tritt Bl\xe7\xa5\xa5lbarde Otto wieder in Aktion. In einem Oster-TV-Special am 28. M\xe5\xb3\xba um 20.15 Uhr strahlt das WDR-Fernsehen die sch\xe7\xaf\xb3ten Sketche und Showauftritte des Ostfriesen aus. 
Hier mal der String in einer Ascii Tabelle (gekürzt):

Code: Alles auswählen

 5
R 82
  37
  180
  179
e 101
l 108
i 105
g 103
e 101
s 115
  32
& 38
  32
C 67
o 111
. 46
: 58
  32
P 80
  37
  175
  171
t 116
l 108
i 105
c 99
h 104
Wenn ich also so einen String durch meinen Test jage, kommt bei keinem Codec was gescheites raus, egal ob ich .encode() oder .decode() nehme... Dabei bin ich einfach mal von Ausgegangen, das irgend ein Codec schon passen wird...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Komisch ist, hin und wieder erscheinen die selben Daten richtig mit Sonderzeichen. d.h. ich kann äöü usw. richtig sehen... Ich hab aber am Code nichts geändert :shock:
Wenn ich es später mal wieder versuche, sind die Sonderzeichen wieder falsch dargestellt :?

Ich sehe da noch keinen Zusammenhang...

EDIT: Da scheind es Probleme mit SciTE zu geben. Hin und wieder erkennt er das encoding des Python-Skripts einfach nicht.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Für mein SQL-Problem http://www.python-forum.de/viewtopic.php?t=3529 habe ich mir das hier gebastelt:

Code: Alles auswählen

def testcodec( txt ):
    "Testet blind alle Codecs mit encode und decode"

    codecs = ['ascii', 'big5', 'big5hkscs', 'cp037', 'cp424', 'cp437', 'cp500',
        'cp737', 'cp775', 'cp850', 'cp852', 'cp855', 'cp856', 'cp857', 'cp860',
        'cp861', 'cp862', 'cp863', 'cp864', 'cp865', 'cp866', 'cp869', 'cp874',
        'cp875', 'cp932', 'cp949', 'cp950', 'cp1006', 'cp1026', 'cp1140', 'cp1250',
        'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', 'cp1257', 'cp1258',
        'euc_jp', 'euc_jis_2004', 'euc_jisx0213', 'euc_kr', 'gb2312', 'gbk', 'gb18030',
        'hz', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_2004',
        'iso2022_jp_3', 'iso2022_jp_ext', 'iso2022_kr', 'latin_1', 'iso8859_2',
        'iso8859_3', 'iso8859_4', 'iso8859_5', 'iso8859_6', 'iso8859_7', 'iso8859_8',
        'iso8859_9', 'iso8859_10', 'iso8859_13', 'iso8859_14', 'iso8859_15', 'johab',
        'koi8_r', 'koi8_u', 'mac_cyrillic', 'mac_greek', 'mac_iceland', 'mac_latin2',
        'mac_roman', 'mac_turkish', 'ptcp154', 'shift_jis', 'shift_jis_2004',
        'shift_jisx0213', 'utf_16', 'utf_16_be', 'utf_16_le', 'utf_7', 'utf_8',
        'idna', 'mbcs', 'palmos',
        'raw_unicode_escape', 'rot_13', 'string_escape',
        'undefined', 'unicode_escape', 'unicode_internal'
    ]
    #~ codecs += [
        #~ 'base64_codec',
        #~ 'bz2_codec',
        #~ 'hex_codec',
        #~ 'punycode',
        #~ 'quopri_codec',
        #~ 'zlib_codec',
        #~ 'uu_codec'
    #~ ]
    for codec in codecs:
        try:
            print txt.encode( codec ), " - encode:", codec
        except:
            pass
        try:
            print txt.decode( codec ), " - decode:", codec
        except:
            pass

testcodec( "Ein ue: ü" )
print "-"*80
testcodec( "latin-1:\xfc" )
print "-"*80
testcodec( "UTF8: \xc3\xbc" )
Die Ausgaben:

Code: Alles auswählen

Ein ue: \xc3\xbc  - encode: string_escape
Ein ue: ü  - decode: string_escape
Ein ue: ü  - encode: unicode_internal
--------------------------------------------------------------------------------
latin-1:\xfc  - encode: string_escape
latin-1:젠- decode: string_escape
latin-1:젠- encode: unicode_internal
--------------------------------------------------------------------------------
UTF8: \xc3\xbc  - encode: string_escape
UTF8: ü  - decode: string_escape
UTF8: ü  - encode: unicode_internal
Wobei ich mit den Ausgaben nicht gerechnet hab. Was ist da falsch? Es müßte doch eigentlich immer ein codec zutreffen... :?:

EDIT am http://p-nand-q.com/python/unicode_faq.html studier...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Nach dem ich nochmal in die oben erwähnte FAQ reingeschaut hab, hier eine neue Variante, die wirklich sinnvoll funktioniert:

Code: Alles auswählen

def testcodec( txt, destination="utf_8" ):
    "Testet blind alle Codecs mit encode und decode"

    codecs = ['ascii', 'big5', 'big5hkscs', 'cp037', 'cp424', 'cp437', 'cp500',
        'cp737', 'cp775', 'cp850', 'cp852', 'cp855', 'cp856', 'cp857', 'cp860',
        'cp861', 'cp862', 'cp863', 'cp864', 'cp865', 'cp866', 'cp869', 'cp874',
        'cp875', 'cp932', 'cp949', 'cp950', 'cp1006', 'cp1026', 'cp1140', 'cp1250',
        'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', 'cp1257', 'cp1258',
        'euc_jp', 'euc_jis_2004', 'euc_jisx0213', 'euc_kr', 'gb2312', 'gbk', 'gb18030',
        'hz', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_2004',
        'iso2022_jp_3', 'iso2022_jp_ext', 'iso2022_kr', 'latin_1', 'iso8859_2',
        'iso8859_3', 'iso8859_4', 'iso8859_5', 'iso8859_6', 'iso8859_7', 'iso8859_8',
        'iso8859_9', 'iso8859_10', 'iso8859_13', 'iso8859_14', 'iso8859_15', 'johab',
        'koi8_r', 'koi8_u', 'mac_cyrillic', 'mac_greek', 'mac_iceland', 'mac_latin2',
        'mac_roman', 'mac_turkish', 'ptcp154', 'shift_jis', 'shift_jis_2004',
        'shift_jisx0213', 'utf_16', 'utf_16_be', 'utf_16_le', 'utf_7', 'utf_8',
        'idna', 'mbcs', 'palmos',
        'raw_unicode_escape', 'rot_13', 'string_escape',
        'undefined', 'unicode_escape', 'unicode_internal'
    ]
    #~ codecs += [
        #~ 'base64_codec',
        #~ 'bz2_codec',
        #~ 'hex_codec',
        #~ 'punycode',
        #~ 'quopri_codec',
        #~ 'zlib_codec',
        #~ 'uu_codec'
    #~ ]
    for codec in codecs:
        try:
            print txt.decode( codec ).encode( destination ), " - codec:", codec
        except:
            pass
    print "-"*80

testcodec( "Ein ue...: ü" )
testcodec( "latin-1..: \xfc" )
testcodec( "UTF8.....: \xc3\xbc" )
Natürlich treffen einige Codec mehr oder weniger zu, aber das muß man dann einfach nachsehen, welcher Codec denn nun wahrscheinlich der richtige ist. Es ist zumindest eine Hilfe, finde ich ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Ich muss hier mal nachhaken... der Artikel ist zwar schon etwas älter aber ne Frage hätte ich trotzdem.

Es lässt sich ja bis heute nur Raten, welches Encoding verwendet wurde.

Aber... wie kann man am besten ran gehen.

ich versuche es immer erst mit

Code: Alles auswählen

import locales

txt = 'ääÖ_ÖüüÄ'

txt.decode(locals.getpreferredcoding())
# richtig geschrieben? :)
Das ist sozusagen das erste --- das ausprobieren...

doch in wie weit macht es Sinn, einfach jedes Encoding durchzuprobieren?

Ich bin mir nicht sicher... aber ist es möglich, das ein und das Selbe Dokument eventuell auf zwei Coding-Typen zutrifft. Ich weiß ja nicht, aber es gibt viele, die sich ähneln.

Gibt es da ein "Erfolgsrezept". Im Moment gehe ich da ganz nach dem Wiki vor... kann natürlich sein, das das schon das "beste" ist... wollte nur nochmal nachfragen.


MfG EnTeQuak
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Natürlich können mehrere Encodings passen... Wenn du z.B. ein Dokument mit nur ASCII Zeichen hast, passen viele Encodings...

Es ist nun mal so, das es keine Meta-Informationen gibt. Einzig das mit dem BOM Tag ist IMHO dafür da...

Somit bleibt einen einfach nichts anderes übrig, als zu raten ;)

Allerdings ist die Frage, woher kommen die Daten? Also es sollte sich normalerweise herausfinden lassen, welches Encoding das richtige ist...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
name
User
Beiträge: 254
Registriert: Dienstag 5. September 2006, 16:35
Wohnort: Wien
Kontaktdaten:

Code: Alles auswählen

>>> a = u"a"
>>> b = "b"
>>> a.__class__ 
<type 'unicode'>
>>> b.__class__
<type 'str'>
>>> b.__class__ == str
True
>>> a.__class__ == str  
False
>>> 
Hier ein Beispiel wie man das encoding von str feststellen kann, zuminders zwischen Unicode und ASCII
Ohloh | Mein Blog | Jabber: segfaulthunter@swissjabber.eu | asynchia – asynchrone Netzwerkbibliothek

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

name hat geschrieben:Hier ein Beispiel wie man das encoding von str feststellen kann, zuminders zwischen Unicode und ASCII
Sowas wird mit ``type`` (``__class__`` zu benutzen ist außerhalb der Klasse unüblich, genauso wie man auch nicht ``__len__`` aufruft sondern len(x))gemacht und hat mit der eigentliche Frage nichts zu tun. Damit stellt man außerdem nicht das Encoding fest sondern an welches Objekt der Name gebunden ist.

Code: Alles auswählen

In [2]: a = u'ü'

In [3]: b = 'ü'

In [4]: type(a)
Out[4]: <type 'unicode'>

In [5]: type(b)
Out[5]: <type 'str'>
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

btw. ich würde das so machen:

Code: Alles auswählen

isinstance(obj, str)
isinstance(obj, unicode)
Das hat aber nichts mit dem encoding zu tun ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Hier der Vergleich von welchen Type a, b ist.

Code: Alles auswählen

In [10]: isinstance(a, unicode)
Out[10]: True

In [11]: isinstance(b, unicode)
Out[11]: False

In [12]: isinstance(a, str)
Out[12]: False

In [13]: isinstance(b, str)
Out[13]: True

In [14]:
EDIT: Jens war schneller ;)
Zuletzt geändert von sape am Donnerstag 1. Februar 2007, 17:21, insgesamt 1-mal geändert.
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

jens hat geschrieben: Es ist nun mal so, das es keine Meta-Informationen gibt. Einzig das mit dem BOM Tag ist IMHO dafür da...
Nein, die BOM ist nur dafür da, um zwischen UTF-16-LE und UTF-16-BE unterscheiden zu können. Für UTF-8 gibt es auch eine, die ist aber als solche eher sinnlos, da dort die Byte Order egal ist.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

birkenfeld hat geschrieben:Nein, die BOM ist nur dafür da, um zwischen UTF-16-LE und UTF-16-BE unterscheiden zu können. Für UTF-8 gibt es auch eine, die ist aber als solche eher sinnlos, da dort die Byte Order egal ist.
War das Utf-8 BOM nicht dafür da damit der Windows Notpad Editor das Zeug wieder lesen kann?

However: jedie sucht chardet. Das was das Script macht ist absolut sinnlos.
TUFKAB – the user formerly known as blackbird
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

blackbird hat geschrieben: However: jedie sucht chardet. Das was das Script macht ist absolut sinnlos.
In der Tat.
Dann lieber noch Vim 7 als Windows 7.

http://pythonic.pocoo.org/
Antworten