wie muss encoding utf8 in erster zeile aussehen?

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
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Hi,

ich habe ab und zu das Problem, dass ich Fehlermeldungen bekomme wie:
'charmap' codec can't encode character '\u20ac' in position 763: character maps to <undefined>
Ich glaube das liegt am utf8.
Und vermutlich kann man das lösen, indem man zu beginn des Skripts das richtige hinschreibt.

Allerdings bin ich absolut verwirrt darüber, was ich nun wirklich genau zu anfang des skripts schreiben muss, da überall etwas anderes steht und merkwürderigerweise auch nur die hälfte davon keinen Syntax Fehler auslöst.
Ich verwende Python 3.4 , gut möglich, dass das wichtig zu wissen ist. Außerdem lasse ich die Skripte testweise auf Windows 8 in der windows powershell laufen und dann schließlich auf Debian 8x64.

Das was ich dachte, was eig richtig ist, ist:

Code: Alles auswählen

# encoding: utf-8
Allerdings hatte ich trotzdem bei manchen dingen zeichenprobleme. Googeln hat mir unzählige Variationen ausgespuckt, wie z.b:

Code: Alles auswählen

# encoding: utf8

Code: Alles auswählen

# coding: utf-8

Code: Alles auswählen

# coding: utf8
Letzteres hatte mein damaliges Problem gelöst.

Das komische ist jetzt aber, dass ein Skript keine Probleme mit "# coding: utf8" hat, während ein anderes Skript in der Zeile sofort einen Snytax Fehler ausspuckt:

Code: Alles auswählen

SyntaxError: encoding problem: utf8
Das hat mich nun vollends verwirrt und ich weiß wirklich nicht, was nun richtig und was falsch ist...

Also bitte klärt mich auf.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Statt herumzuraten, schau dir einfach mal das PEP an: https://www.python.org/dev/peps/pep-0263/

Und ja, es gibt mehrere Varianten.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

cofi hat geschrieben:Statt herumzuraten, schau dir einfach mal das PEP an: https://www.python.org/dev/peps/pep-0263/

Und ja, es gibt mehrere Varianten.
Okay, super, noch viel mehr Varianten...
Aber wo steht dort, warum die eine Variante in dem einen Skript klappt und woanders wieder nicht?

Habe mich dann jetzt für

Code: Alles auswählen

# coding=utf-8
entschieden, zumindest löst das keinen Syntaxerror aus und scheinbar ist der zeichenfehler auch weg. Insofern schonmal danke :)

edit:
ne der Zeichenfehler ist leider doch nicht weg =/

Code: Alles auswählen

UnicodeEncodeError: 'charmap' codec can't encode character '\u20ac' in position 568: character maps to <undefined>
BlackJack

@Serpens66: Die Varianten funktionieren alle in jedem Quelltext, solange der Name der Kodierung zur tatsächlichen Kodierung des Quelltextes passt.

Die Ausnahme die Du zeigst hat nichts mit der Kodierung des Quelltextes und dem Kodierungskommentar zu tun, denn das ist eine Ausnahme die beim *kodieren* ausgelöst wird. Da wissen wir jetzt nicht woher die kommen und auch nicht wohin die gehen, also wer, warum, wie versucht die zu kodieren.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

BlackJack hat geschrieben:@Serpens66: Die Varianten funktionieren alle in jedem Quelltext, solange der Name der Kodierung zur tatsächlichen Kodierung des Quelltextes passt.

Die Ausnahme die Du zeigst hat nichts mit der Kodierung des Quelltextes und dem Kodierungskommentar zu tun, denn das ist eine Ausnahme die beim *kodieren* ausgelöst wird. Da wissen wir jetzt nicht woher die kommen und auch nicht wohin die gehen, also wer, warum, wie versucht die zu kodieren.
Das "Ding" was ich printen will, ist eine Antwort von der websocket die ich hier versuche anzuzapfen:
viewtopic.php?f=1&t=38120&p=292370#p292370

Und zwar gibts da soweit ich es mitbekommen habe mind. 3 verschiedene Dinge, die mir die websocket ausgibt. 1) Die "begrüßung", ein print ist dann:
1::
Und dann gibt es noch die 2 Events, die in der Dokumenation der websocket beschrieben sind. "remove_order" und "add_order".

Führe ich das websocket skript aus und versuche jeweils die antwort zu printen bekomme ich folgendes:

Code: Alles auswählen

1::
5:::{"name":"remove_order","args":[{"id":"1912565","order_id":"E69X7T","order_type":"buy","type":"order","reason":"0yzjO
GFy3vQgfFm0re8.","trade_user_id":"0yybQ5oPojghf0rhqQ.."}]}
5:::{"name":"remove_order","args":[{"id":"1912548","order_id":"W8V3VU","order_type":"sell","type":"offer","reason":"0yzj
OGFy3vQgfFm0re8.","trade_user_id":"0yybRBoNogkkfFW0rrI."}]}
Traceback (most recent call last):
  File "meine_ws2.py", line 69, in <module>
    asyncio.get_event_loop().run_until_complete(handler())
  File "C:\Python34\lib\asyncio\base_events.py", line 268, in run_until_complete
    return future.result()
  File "C:\Python34\lib\asyncio\futures.py", line 277, in result
    raise self._exception
  File "C:\Python34\lib\asyncio\tasks.py", line 236, in _step
    result = next(coro)
  File "meine_ws2.py", line 62, in handler
    print(message)
  File "C:\Python34\lib\encodings\cp850.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_map)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u20ac' in position 743: character maps to <undefined>
Bei all meinen Versuchen kam bisher immer nur diese Begrüßung und das remove_order Event.
Daher schließe ich daraus, dass das "Add_order" event eben dieses Zeichen enthält, welches einen Fehler auslöst und das ganze beendet.

Die Frage ist nun also, wie ich es schaffe, das "add_order" event auszugeben.
BlackJack

@Serpens66: Wie man sieht versuchst Du das auf einer Ausgabe auszugeben die cp850 als Kodierung erwartet. '\u20ac' ist das Eurozeichen (€) und cp850 kennt kein Eurozeichen, also kann man das Eurozeichen auch nicht als cp850 kodieren. Stell die Kodierung im Terminal (vermute ich jetzt mal) auf etwas um das das Eurozeichen darstellen kann, oder kodiere selbst als cp850, so dass Zeichen die nicht kodiert werden können durch etwas anderes ('?') ersetzt werden (optionales Argument bei `encode()`).
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

BlackJack hat geschrieben:@Serpens66: Wie man sieht versuchst Du das auf einer Ausgabe auszugeben die cp850 als Kodierung erwartet. '\u20ac' ist das Eurozeichen (€) und cp850 kennt kein Eurozeichen, also kann man das Eurozeichen auch nicht als cp850 kodieren. Stell die Kodierung im Terminal (vermute ich jetzt mal) auf etwas um das das Eurozeichen darstellen kann, oder kodiere selbst als cp850, so dass Zeichen die nicht kodiert werden können durch etwas anderes ('?') ersetzt werden (optionales Argument bei `encode()`).
Ah, vielen dank :)

Code: Alles auswählen

print(message.encode("utf-8"))
das hat das Problem gelöst, das Zeichen wird nun offenbar durch "\xc2\xa0\xe2\x82\xac" ersetzt.
Das Ergebnis bleibt aber dasselbe, auch wenn ich schreibe:

Code: Alles auswählen

print(message.encode("utf-8","replace"))
Ich dachte wenn ich replace verwende, wird alles durch ein ? ersetzt? Wird es aber scheinbar nicht. Oder was mache ich falsch?

Von diesem Codierungsproblem ist alles betroffen, oder? Dh. ich sollte den string nicht nur im print encoden, sondern einfach direkt beim abseichern in einer variablen, den encodeten string absspeichern, richtig?
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Hier findet man ein paar vorschläge, aber wirklich überzeugen zun die glaub ich nicht, oder?
http://stackoverflow.com/questions/1463 ... -undefined

am besten gefällt mir in der zweiten Antwort die funktion:

Code: Alles auswählen

def uprint(*objects, sep=' ', end='\n', file=sys.stdout):
    enc = file.encoding
    if enc == 'UTF-8':
        print(*objects, sep=sep, end=end, file=file)
    else:
        f = lambda obj: str(obj).encode(enc, errors='backslashreplace').decode(enc)
        print(*map(f, objects), sep=sep, end=end, file=file)
hier wird das € zeichen durch '\u20ac' ersetzt.
Allerdings ist da nun die Frage, ob diese Funktion nur mit print funktioniert.

Letzlich will ich die Antworten ja so nicht printen, sondern ich möchte die Daten auslesen.
Mit uprint() sieht das add_order" event nun so aus:

Code: Alles auswählen

5:::{"name":"add_order","args":[{"id":"1912831","type":"offer","amount":"10","min_amount":"0.1775","price":"386.72","vol
ume":"3867.20","min_trust_level":"bronze","only_kyc_full":"0","seat_of_bank_of_creator":"de","bic_short":"0yzjPeTwlzkig1
B-","bic_full":"0yzjPeTw33DssfxIB4io2Mow-w..","uid":"0ywbQpkIozshf3HhqA..","trade_to_sepa_country":"[\"DE\",\"AT\",\"CH\
",\"DK\",\"NL\",\"NO\",\"SE\"]","is_shorting":"0","is_shorting_allowed":"0","is_trade_by_sepa_allowed":"0","is_trade_by_
fidor_reservation_allowed":"1","fidor_account":"0","is_kyc_full":"1","price_de":"386,72 \u20ac","volume_de":"3.867,20 \u
20ac","amount_de":"10","min_amount_de":"0,1775","country_payment_method_de":"Deutschland","price_formatted_de":"386,72 "
,"price_en":"\u20ac386.72","volume_en":"\u20ac3,867.20","amount_en":"10","min_amount_en":"0.1775","country_payment_metho
d_en":"Germany","price_formatted_en":"386.72","price_fr":"386,72 \u20ac","volume_fr":"3 867,20 \u20ac","amount_fr":"10",
"min_amount_fr":"0,1775","country_payment_method_fr":"Allemagne","price_formatted_fr":"386,72 ","price_es":"\u20ac 386,7
2","volume_es":"\u20ac 3.867,20","amount_es":"10","min_amount_es":"0,1775","country_payment_method_es":"Alemania","price
_formatted_es":" 386,72","price_it":"\u20ac 386,72","volume_it":"\u20ac 3.867,20","amount_it":"10","min_amount_it":"0,17
75","country_payment_method_it":"Germania","price_formatted_it":" 386,72","order_id":"KQYN3P","order_type":"sell","payme
nt_option":"1"}]}
Letzlich will ich daraus ja nur die einträge extrahieren. also beim price brauch ich nur die Zahl und nicht das euro zeichen.
Muss ich da die antwort nun vorher auch encoden, oder nicht?
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: natürlich mußt Du die Antwort nicht encoden. Intern arbeitest Du ja immer mit Unicode. Und dass Du den String, den Du aus dem Wörterbuch herausliest von seinem € trennen willst, ist ja eine ganz andere Frage, die Du hoffentlich inzwischen selbst beantworten kannst.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Sirius3 hat geschrieben:@Serpens66: natürlich mußt Du die Antwort nicht encoden. Intern arbeitest Du ja immer mit Unicode. Und dass Du den String, den Du aus dem Wörterbuch herausliest von seinem € trennen willst, ist ja eine ganz andere Frage, die Du hoffentlich inzwischen selbst beantworten kannst.
okay danke :)

mal überlegen, wie ich "200 €" bzw. "200 \u20ac" sicher trennen kann...
spontan fällt mir da eigentlich nur ein

Code: Alles auswählen

.replace("€","")
, dafür musste ich ja allerdings wissen, ob intern das € zeichen erkannt wird. Wird es aber wie du schreibst, hab ich das richtig gedeutet?

Also wenn
str = "200,32 €"
dann kann ich einfach
price = float(str.replace("€",""))
machen, oder?

edit:
Oh man, es geht tatsächlich hundertmal einfacher mit replace :D Vorraussetzung ist natürlich, dass man weiß was die Antwort für besondere Zeichen enthalten wird. Also wenn ich nun weiß, dass € das böse Zeichen ist, kann ich beim printen (oder auch allgemein die antwort umwandeln, um auf nummer sicherzugehen, dass kein nachträgliches printen schiefgeht) einfach machen:

Code: Alles auswählen

print(message.replace("€","EUR"))
BlackJack

@Serpens: b'\xc2\xa0\xe2\x82\xac' ist nicht nur das €-Zeichen UTF-8 kodiert, sondern ein Leerzeichen an dem nicht umgebrochen werden soll, gefolgt von einem €-Zeichen.

Wenn man 'replace' angibt werden Unicode-Zeichen die nicht kodiert werden können durch ein '?' ersetzt. UTF-8 kann aber alles kodieren, deswegen nimmt man das ja auch gerne weil es damit keine solchen Probleme gibt wie bei Kodierungen bei denen ein Byte ein Zeichen ist und damit nur maximal 256 verschiedene Zeichen kodiert werden können.

Code: Alles auswählen

In [6]: s = u'42\xa0\u20ac'

In [7]: print s
42 €

In [8]: s.encode('cp850')
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-8-902013fb5a2a> in <module>()
----> 1 s.encode('cp850')

/usr/lib/python2.7/encodings/cp850.pyc in encode(self, input, errors)
     10 
     11     def encode(self,input,errors='strict'):
---> 12         return codecs.charmap_encode(input,errors,encoding_map)
     13 
     14     def decode(self,input,errors='strict'):

UnicodeEncodeError: 'charmap' codec can't encode character u'\u20ac' in position 3: character maps to <undefined>

In [9]: s.encode('cp850', 'replace')
Out[9]: '42\xff?'
Antworten