□? Ä!
Encoding in der Praxis Thomas Jacob Hamburg, 02. Dezember 2009
Warum gibt es Encoding? Mensch
Computer
Ä A
1100101
Code-Charts: z.B. ISO-8859-1
Warum gibt es Encoding? Mensch
Computer
Ä A
196 String
Byte Character
Code-Point
Reader / Writer Encoding
Decoding
Streams
Was sind populäre Code-Charts? US-ASCII: Nutzt nur die Codes 0 bis 127, keine Umlaute etc, „amerikanisch“ ISO-8859-1: Nutzt 8 Bit, Codes 0 bis 255, „west-europäisch“, aber kein Euro-Zeichen ISO-8859-15: Ähnlich wie ISO-8859-1, aber ein paar Anpassungen wie Euro-Zeichen CP-1252: Von Microsoft eingeführt, ähnlich wie ISO-8859-1, aber mit Euro-Zeichen Unicode: Unterstüzt „alle“ Zeichen, braucht aber auch 4 Bytes je Code Kompromisse:
_
UTF-8 braucht meist 1 Byte, kann aber auch bis zu 4 Bytes brauchen (meist 1-3)
_
UTF-16 braucht fast immer 2 Bytes je Zeichen, nur sehr spezielle brauchen mehr
Fazit: UTF-8 ist meistens das beste Encoding, platzsparend und mächtig
Abgrenzung der Begriffe Encoding Umwandeln eines Strings in einen Byte-Array, in Java string.getBytes(encoding) Decoding Umwandeln eines Byte-Arrays in einen String, in Java new String(bytes, encoding) Escaping Problematische Zeichen ersetzen, z.B. ä oder \n, weil sie sich nicht abbilden lassen oder eine andere Bedeutung haben. Kein Encoding/Decoding, wir bleiben in der String-Welt. In Java StringEscapeUtils (commons gehört allgemein unters Kopfkissen). URL-Encoding Encoding und anschließendes Decoding in Hex-Notation (es bleibt ein String). Ein Ä in ISO-8859-1: %C0, ein Ä in UTF-8: %C3%84 In Java URLEncoder und URLDecoder (Vorsicht, mit Encoding!) URL-Rewriting Fügt nur die Session-ID an, die Methode heißt nur doof: response.encodeURL(url) Line-Encoding Die Bytes, die für das Newline verwendet werden, 13, 10 oder 13 und 10. Recoding Ein falsches Encoding durch ein falsches Decoding wieder reparieren. (Kategorie „üble Hacks“, macht die Wikipedia zur Datenbank-Kompatibilität)
Ein Request-Response-Zyklus Ä Ä
Internet
196
196
Netzwerk
196 196
Mit Request, Response, Datenbank und Service: 17 mal Encoding oder Decoding!
Ä Ä 196
Ä 196
196
Netzwerk
196
Internet
196
Ä JSP
196
Grundregeln Alle Orte, an denen Encodings stattfinden, kennen Stets wissen, ob man in der String- oder Byte-Welt ist Gedanklich alle Encoding- und Decoding-Schritte durchspielen Niemals sich auf Defaults verlassen (APIs, Einstellungen) Mit typischen Kandidaten testen: Umlaute, Euro-Zeichen, ostasiatische Schriftzeichen, Leerzeichen, Umbrüche, etc.
Probleme erkennen: Klassifizierung Vielen Dank f�r die Blumen! Beim Decoding wurde ein Code-Point nicht gefunden. Dies tritt auf, wenn mit ISO oder CP1252 encodet und mit UTF-8 decodet wurde. Manchmal fehlt auch einfach das Zeichen in der Schriftart. Vielen Dank fÄr die Blumen! Beim Decoding wurden die zwei Code-Points als zwei Zeichen interpretiert. Dies tritt auf, wenn mit UTF-8 encodet und mit ISO oder CP1252 decodet wurde. Vorsicht: Bei Server-Konsolen kommt zur Darstellung wieder ein Encoding zum Zug! Auch mal selbst mit rumspielen:
public class EncodeTester { public static void main(String[] args) throws Exception { String string = "Ä"; byte[] bytes = string.getBytes("UTF-8"); string = new String(bytes, "ISO-8859-1"); System.out.println(string); } }
Probleme erkennen: Örtliche Eingrenzung Örtliche Eingrenzung Den Punkt finden, an dem das Encoding falsch ist:
_
Testen und Debuggen
_
Formular vs. Schnittstelle vs. Applikations-Dateien
_
Request vs. Response
_
Nur auf Produktion? Nur auf Linux? Nur bei mir? Nur bei einem User?
Typische Fehler Böse API Methoden, die Umwandeln, aber kein Encoding nehmen, vermeiden: new String(byte[]): böse string.getBytes(): böse InputStreamReader(stream): böse URLEncoder.encode(url): böse Falsche Einstellung im Editor Besonders fies: Es sieht richtig aus. Nur einigen und richtig einstellen hilft. Falsche Encoding-Einstellungen im Container Im Tomcat werden GET-Requests in der server.xml eingestellt POST-Requests müssen per Filter angegeben werden (muss der erste sein!) z.B. org.springframework.web.filter.CharacterEncodingFilter Datenbank Verbindungs- und Persistenzencoding einstellen, z.B. in der JDBC-URL Schnittstellen Dokumentation beachten, ggf. Encoding vereinbaren
Vielen Dank. Mehr hier: http://dev.sinnerschrader.de/Encoding-Probleme http://de.wikipedia.org/wiki/ISO-8859-1 http://de.wikipedia.org/wiki/UTF-8 http://vietunicode.sourceforge.net/howto/java/encoding.html http://de.wikipedia.org/wiki/URL_Encoding http://www.eki.ee/letter
SinnerSchrader Deutschland GmbH Völckersstrasse 38 22765 Hamburg T 040.398855-0 F 040.398855-55 www.sinnerschrader.de
[email protected]