[✓] Eigenartiges Codierungsproblem

Smalltalk
Antworten
Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

[✓] Eigenartiges Codierungsproblem

Beitrag von paedubucher » 26.01.2019 14:29:00

Bei einem Dateiupload im einer Web-Applikation habe ich ein eigenartiges Codierungsproblem. Die technologischen Details lasse ich mal aussenvor, nur soviel: es handelt sich um ein Angular-Frontend (JavaScript), das eine Datei in ein Spring-Boot-Backend (Java) hochlädt.

Lade ich eine Datei namens ö.pdf unter macOS/Firefox hoch, kommt der Dateiname dort als oÌ.pdf an. Unter Linux/Firefox heisst sie ö.pdf nach dem Upload. Da es zwischen macOS und Linux einen Unterschied gibt, dürfte der Fehler eher auf Frontend-Seite sein.

Ich habe mir mal die Codierungen für diese Zeichen heausgesucht (dargestelltes Zeichen, Unicode-Codepoint und UTF-8-Kodierung hexadezimal und binär):
  • ö: U+00f6, 0xc3 0xb6, 11000011 10110110
  • Ì: U+00cc, 0xc3 0x8c, 11000011 10001100
  • Ã: U+00c3, 0xc3 0x83, 11000011 10000011
  • ¶: U+00b6, 0xc2 0xb6, 11000010 10110110
Verdächtig ist, dass die beiden Zeichen Ì und à in der UTF-8-Codierung jeweils mit einem 0xc3 anfangen. Beim zweiten Byte passiert dann irgend eine Transformation, die ich noch nicht begreife.

Hat jemand eine Idee, wo ich da ansetzen könnte? Lokale Codierungs- und Zeichensatzoptionen gibt es Haufenweise, von daher weiss ich nicht, ob ich irgendwelche nützlichen Angaben machen kann. Auf der Linux-Kiste steht etwa bei mir LANG=en_US.UTF-8 in /etc/locale.conf. (Auf dem Macbook müsste ich montags im Büro nachschauen, wobei ich da mit den Einstellungen noch weniger vertraut bin als auf Linux.)
Zuletzt geändert von paedubucher am 27.01.2019 11:45:59, insgesamt 2-mal geändert.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
novalix
Beiträge: 1909
Registriert: 05.10.2005 12:32:57
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: elberfeld

Re: Eigenartiges Codierungsproblem

Beitrag von novalix » 26.01.2019 16:49:21

Hi,

ich würde davon ausgehen, dass die Client-Systeme UTF-8 codiert sind. Andernfalls ist entweder die Installation steinalt oder Du hast explizit eine andere Codierung ausgewählt, was Du dann wohl wissen würdest.

Code: Alles auswählen

export | grep LANG
zeigt Dir die Codierung Deines Environments.
Wenn Du noch einen anderen Browser installiert hast, kannst Du noch ausschließen, dass es an Firefox liegt (eher unwahrscheinlich, imho).
Der nächste Schritt wäre dann den JS-Code zu debuggen. Es könnte allerdings sein, dass Dir das relativ wenig nützt, wenn auf Seiten der Implementierung Mist gebaut wurde.
Eine Suche nach "Angular Umlaut" fördert einige Ergebnisse dieser Art zu Tage: https://stackoverflow.com/questions/206 ... -correctly
Bliebe dann allerdings immer noch die Frage, warum zwei verschiedene Auswirkungen auftreten.
Das Wem, Wieviel, Wann, Wozu und Wie zu bestimmen ist aber nicht jedermannns Sache und ist nicht leicht.
Darum ist das Richtige selten, lobenswert und schön.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von Meillo » 26.01.2019 16:55:30

Solcher Zeichensalat kommt normalerweise dann raus, wenn man Zeichen in einem anderen Encoding interpretiert als sie abgespreichert worden sind.

Wenn aus einem Zeichen zwei werden, dann wird das in einem Multibyte-Encoding gespeichert und in einem Singlebyte-Encoding interpretiert worden sein.

Suche dir also die UTF-8-Kodierung fuer das ``ö'' raus. Das werden zwei Bytes sein. Schaue dann fuer was diese zwei Bytes in Latin1 o.ae. stehen (dort werden es zwei einzelne Zeichen sein). Auf diesem Weg solltest du fuendig werden.


Das Problem wird nicht dadurch verursacht, dass man unterschiedliche Encodings verwendet, sondern dadurch, dass man das was in einem Encoding gespeichert worden ist in einem anderen rausliest.

Zum Verstaendnis: Unterschiedliche Encodings zu verwenden ist wie Casten in C. Die Bedeuting wird konvertiert. Das geht je nach Datentyp- bzw. Encoding-Konstellation besser oder schlechter.

Das was in deinem Beispiel aber passiert entspricht in C einer Union in die du Typ A reinspeicherst und Typ B rausliest: das funktioniert nur zufaellig mal korrekt ist aber inhaltlich falsch.
Use ed once in a while!

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von paedubucher » 27.01.2019 09:48:15

@novalix

Code: Alles auswählen

$ export | grep LANG
declare -x LANG="en_US.UTF-8"
$ env | grep LANG
LANG=en_US.UTF-8
Chromium hat das gleiche Verhalten, zumindest auf Linux (macOS teste ich noch). Beim JS-Code habe ich schon mit console.log() debuggt, da kommt schon das richtige raus.

Und der String ist ja nicht in der JavaScript-Datei definiert, von daher dürfte die Codierung der Quellcodedatei keine Rolle spielen.

@meillo

Danke für den Tipp mit latin1. Auf Wikipedia steht 0x00f6, was dann binär 11110110 lautet. Ich kann mich noch dunkel daran erinnern, dass ich im Büro irgend eine Differenz berechnet habe, und dabei das Resultat 9 herauskam. Und hier sind genau das 8er und das 1er Bit nicht gesetzt. Das könnte schon mal eine gute Spur sein!

EDIT: Ach blöd, soweit war ich schon. Ich hatte nur in meinem ersten Post 0xfc statt 0xf6 geschrieben :cry:

EDIT 2: Bei à stimmt das erste, bei ¶ das zweite Byte überein:

Code: Alles auswählen

ö 11000011 10110110
à 11000011 10000011
¶ 11000010 10110110
EDIT 3: Dekomposition ist eine Möglichkeit, zumal aus einem Zeichen zwei werden:

Python sagt:

Code: Alles auswählen

>>> import unicodedata
>>> unicodedata.decomposition('ö')
'006F 0308'
>>> bin(0x0308)
'0b1100001000'
>>> bin(0x006f)
'0b1101111'

>>> bin(0xf6)
'0b11110110'
>>> bin(0x6f)
'0b1101111'
Das wäre umgedreht das gleiche. Zufall?

EDIT 4:

Python sagt noch mehr:

Code: Alles auswählen

>>> u'\xf6'.encode('utf-8')
b'\xc3\xb6'
>>> u'\xc3\xb6'.encode('utf-8')
b'\xc3\x83\xc2\xb6'
8O

Das Problem ist hier vor meinen Augen, aber ich verstehe die Logik dahinter noch nicht. Wird hier einmal zuviel codiert?

EDIT 5: Jetzt kann ich es nachvollziehen!

Code: Alles auswählen

>>> 'ö'.encode('utf-8').decode('latin1')
'ö'
Wenn die zwei UTF-8 kodierten Bytes von ö als latin1 interpretiert werden, wird jedes Byte als einzelnes Zeichen verstanden! (Genau was Meillo vermutete! Danke dafür!) :D
Zuletzt geändert von paedubucher am 27.01.2019 11:39:36, insgesamt 1-mal geändert.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von Meillo » 27.01.2019 11:25:47

paedubucher hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 09:48:15
EDIT 2: Bei à stimmt das erste, bei ¶ das zweite Byte überein:

Code: Alles auswählen

ö 11000011 10110110
à 11000011 10000011
¶ 11000010 10110110
Ich glaube, du verstehst das Problem noch nicht ganz.

Dein Beispiel hier ist komplett in der UTF-8-Welt. Das Problem kommt aber von einer unerlaubten Vermischung von Encodings, also vom Wechsel zwischen Encoding-Welten.

In erklaer's dir nochmal:

Auf der einen Seite gibt es schreibenden Code. Der soll ein ``ö'' schreiben. Er schreibt es UTF-8-kodiert. Folglich schreibt er folgende zwei Bytes: 0xC3 0xB6.

Auf der anderen Seite gibt es lesenden Code. Dieser denkt sich -- warum auch immer -- dass er Bytes die er liest am liebsten nach Latin1 dekodiert. Er liest 0xC3, schaut in der Latin1-Charset-Tabelle nach und findet an der Stelle 0xC3 das Zeichen ``Ã''. Dann liest er 0xB6, schaut nach und findet ``¶''.

Haette der lesende Code die Bytes im gleichen Encoding gelesen wie wie gespeichert worden sind, dann waere auch das Richtige wieder rausgekommen.


Hier ein Beispielprogramm, das das gleiche Prinzip mittels Unions in C demonstriert, sozusagen als technische Analogie:

Code: Alles auswählen

#include <stdio.h>
#include <string.h>

int
main()
{
        union {
                int i;
                float f;
                char s[4];
        } u;

        u.i = 15;
        printf("read a stored int as int: %d\n", u.i);
        printf("read a stored int as float: %f\n", u.f);
        printf("read a stored int as string: %s\n", u.s);
        printf("\n");

        strncpy(u.s, "abc", sizeof(u.s));
        u.s[sizeof(u.s)] = '\0';
        printf("read a stored string as int: %d\n", u.i);
        printf("read a stored string as float: %f\n", u.f);
        printf("read a stored string as string: %s\n", u.s);
        printf("\n");

        u.f = 3.141592;
        printf("read a stored float as int: %d\n", u.i);
        printf("read a stored float as float: %f\n", u.f);
        printf("read a stored float as string: %s\n", u.s);

        return 0;
}

Sein Output (auf meinem System, denn wenn man falsche Typen rausliest ist das Ergebnis undefiniert):

Code: Alles auswählen

B-) make union  
cc     union.c   -o union

B-) ./union
read a stored int as int: 123456
read a stored int as float: 0.000000
read a stored int as string: @

read a stored string as int: 6513249
read a stored string as float: 0.000000
read a stored string as string: abc

read a stored float as int: 1078530008
read a stored float as float: 3.141592
read a stored float as string: I@

B-)

Weniger technisch findest du das gleiche Problem dann, wenn jemand Spanisch schreibt und die andere Person Portugiesisch liest. Das funktioniert teilweise, weil die Sprachen verwandt sind (wie UTF-8 und Latin1 auch), aber an manchen Stellen versteht der Leser nur Quatsch, weil es ein diese spanischen Worte in Portugiesisch nicht gibt (das ist wie dein ``ö'' oder der Float als String gelesen) oder er versteht etwas Falsches (False Friends oder der Float als Int gelesen).


Du musst dir keine Bits anschauen. Es geht nur um die Interpretation von Bytes. Es geht um das Encoding, in dem geschrieben und gelesen wird. Dieses muss natuerlich das gleiche sein.

Man kann schon auch zwischen Encodings uebersetzen, aber das bedarf eines aktiven Vorgangs (d.h. ein Programm muss das tun). Beim Lesen von Daten aber muss immer das gleiche Encoding verwendet werden wie zum Schreiben verwendet wurde. Das ist eigentlich logisch. Bloss wird (wie bei der Union auch) nicht vermerkt, in welchem Encoding gespeichert worden ist. Das muss man halt irgendwie wissen. Wenn immer klar waere, wie etwas zu interpretieren waere, dann wuerde dein Problem gar nicht auftreten.

Ich hoffe, das konnte das Problem damit klarer machen.
Use ed once in a while!

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von Meillo » 27.01.2019 11:28:05

paedubucher hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 09:48:15
EDIT 5: Jetzt kann ich es nachvollziehen!

Code: Alles auswählen

>>> 'ö'.encode('utf-8').decode('latin1')
'ö'
Wenn die zwei UTF-8 kodierten Bytes von ö als latin1 interpretiert werden, wird jedes Byte als einzelnes Zeichen verstanden! :D
Ja, jetzt hast du's verstanden.

... da haette ich ja bloss warten brauchen, dann haette ich mir meinen langen Post sparen koennen. :-P ;-)
Use ed once in a while!

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von paedubucher » 27.01.2019 11:45:01

Meillo hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 11:25:47
Ich hoffe, das konnte das Problem damit klarer machen.
Die Union-Analogie ist genial! Ich habe mich da wirklich zu stark auf Bits konzentriert, um dem Problem auf den Grund zu gehen. Es geht aber nicht um die Bits, sondern um deren Interpretation.

Ein Forumsthread hilft mir manchmal dabei, meine Gedanken sortieren. Treten beim Ausformulieren Zweifel auf, ist das oft ein guter Ansatzpunkt. Ich sollte in Zukunft meine Forenthreads lokal in eine Textdatei schreiben, und ihn erst posten, wenn ich nicht weiterkomme.

Danke aber für deine Mühe! Die Analogie veranschaulicht den Knoten, den ich hatte!
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von paedubucher » 27.01.2019 11:47:54

Meillo hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 11:28:05
... da haette ich ja bloss warten brauchen, dann haette ich mir meinen langen Post sparen koennen. :-P ;-)
Ich glaube das Problem gab es auch schon einmal bei den Simpsons :lol:
(Bezieht sich auf deinen Meme-Thread bzw. den Southpark-Verweis dazu.)
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
Meillo
Moderator
Beiträge: 8813
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von Meillo » 27.01.2019 12:08:01

paedubucher hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 11:47:54
Meillo hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 11:28:05
... da haette ich ja bloss warten brauchen, dann haette ich mir meinen langen Post sparen koennen. :-P ;-)
Ich glaube das Problem gab es auch schon einmal bei den Simpsons :lol:
(Bezieht sich auf deinen Meme-Thread bzw. den Southpark-Verweis dazu.)
:lol: Ja. :THX:

Die Leute sollten mehr Simpsons gucken.


Edit:
Btw: Sind die Simpsons eigentlich auch schon mal auf die Idee gekommen, dass einfach alle UTF-8 verwenden koennten und man haette keine derartigen Probleme mehr? Ach, nein, das waeren ja die Typen aus den Bell Labs ... ;-)
Use ed once in a while!

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von paedubucher » 27.01.2019 12:41:08

Meillo hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 12:08:01
paedubucher hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 11:47:54
Meillo hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 11:28:05
... da haette ich ja bloss warten brauchen, dann haette ich mir meinen langen Post sparen koennen. :-P ;-)
Ich glaube das Problem gab es auch schon einmal bei den Simpsons :lol:
(Bezieht sich auf deinen Meme-Thread bzw. den Southpark-Verweis dazu.)
Btw: Sind die Simpsons eigentlich auch schon mal auf die Idee gekommen, dass einfach alle UTF-8 verwenden koennten und man haette keine derartigen Probleme mehr? Ach, nein, das waeren ja die Typen aus den Bell Labs ... ;-)
Meine Python-Installation kennt 323 Encodings, wobei einige davon Aliase sind. Am Montag muss ich mich durch den ganzen Stack durchhangeln und schauen, wo nicht explizit UTF-8 verwendet wird.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
novalix
Beiträge: 1909
Registriert: 05.10.2005 12:32:57
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: elberfeld

Re: Eigenartiges Codierungsproblem

Beitrag von novalix » 27.01.2019 15:39:41

paedubucher hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 09:48:15
Beim JS-Code habe ich schon mit console.log() debuggt, da kommt schon das richtige raus.

Und der String ist ja nicht in der JavaScript-Datei definiert, von daher dürfte die Codierung der Quellcodedatei keine Rolle spielen.
Disclaimer: Ich verstehe wenig bis gar nichts von den Internals von Angular.
Es gibt ja einen Kommunikationsweg zwischen Client und Server. Usereingaben werden wohl als JSON-Objekte auf die Reise geschickt. Wenn das Template für ein JSON-Objekt eine unzureichende Codierung verwendet, schlägt die Interpretation (ohne ä, scnr) fehl.[*] Zusätzlich besteht dann ja auch noch die Möglichkeit, dass die serverseitige Bearbeitung (Java-Code, DB) nicht hinreichend arbeitet.

[*]Ich fand das interessant, dass solche Fehler anscheinend häufig entstehen, weil die verwendeten fetten IDEs einfach Murks bauen. Webentwicklung auf Windows heißt wohl nicht selten: notepad++ for the rescue.
Das Wem, Wieviel, Wann, Wozu und Wie zu bestimmen ist aber nicht jedermannns Sache und ist nicht leicht.
Darum ist das Richtige selten, lobenswert und schön.

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: Eigenartiges Codierungsproblem

Beitrag von paedubucher » 27.01.2019 19:43:03

novalix hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 15:39:41
paedubucher hat geschrieben: ↑ zum Beitrag ↑
27.01.2019 09:48:15
Beim JS-Code habe ich schon mit console.log() debuggt, da kommt schon das richtige raus.

Und der String ist ja nicht in der JavaScript-Datei definiert, von daher dürfte die Codierung der Quellcodedatei keine Rolle spielen.
Disclaimer: Ich verstehe wenig bis gar nichts von den Internals von Angular.
Es gibt ja einen Kommunikationsweg zwischen Client und Server. Usereingaben werden wohl als JSON-Objekte auf die Reise geschickt. Wenn das Template für ein JSON-Objekt eine unzureichende Codierung verwendet, schlägt die Interpretation (ohne ä, scnr) fehl.[*] Zusätzlich besteht dann ja auch noch die Möglichkeit, dass die serverseitige Bearbeitung (Java-Code, DB) nicht hinreichend arbeitet.
Es gibt sehr viele Usereingaben in diesem Projekt, die problemlos mit Sonderzeichen funktionieren. Hier in diesem Fall geht es um einen Multipart-Request, bei dem nur der Dateiname Probleme macht. (Gleichzeitig werden Metaangaben übermittelt, die keine Probleme machen.) Von daher dürfte das Problem schon eher auf dem Server sein. Aber ich kann morgen mehr Auskunft geben.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Benutzeravatar
paedubucher
Beiträge: 856
Registriert: 22.02.2009 16:19:02
Lizenz eigener Beiträge: GNU Free Documentation License
Wohnort: Schweiz
Kontaktdaten:

Re: [✓] Eigenartiges Codierungsproblem

Beitrag von paedubucher » 10.03.2019 17:10:18

Der Thread ist nun doch schon etwas älter, aber ich möchte dennoch abschliessende Auskunft darüber geben, wie ich das Problem schlussendlich gelöst habe. Klar war, dass da irgend ein Codierungsproblem besteht. Ausserdem hatte ich auf macOS und Linux jeweils andere Codierungsfehler. Es musste also irgendwo am Client liegen. Da das Frontend mit Angular geschrieben ist, und ich unter Zeitdruck stand, habe ich einfach den Dateinamen auf dem Client base64 codiert und übermittelt. Auf dem Backend musste ich das dann wieder decodieren und normalisieren (Unicode NFC), und hinten kam dann wieder das raus, was vorne reingekommen ist.
Habe nun, ach! Java
Python und C-Sharp,
Und leider auch Visual Basic!
Durchaus programmiert mit heissem Bemühn.
Da steh' ich nun, ich armer Tor!
Und bin so klug als wie zuvor.

Antworten