UNICODE

Java a čeština? Unicode!

unicode


Stručně o Unicode

Světový standard kódování znaků Unicode Worldwide Character Standard zavedlo Unicode Consorcium jako systém znaků určený pro podporu výměny, zpracování a zobrazování psaného textu v rozličných jazykových verzích moderního světa.

Oproti kódování ASCII a dalším jednobajtovým kódováním, ve kterých je každý znak uložen na 8 bitech, je v kódováních Unicode jeden znak uložen na jednom a více bajtech. Znaky Unicode je do bajtů možné kódovat vícero kódováními: kódovacími schématy Unicode Transformation Formats (UTF) nebo Universal Character Set (UCS). Mezi nejdůležitější patří UTF-8, které kóduje znaky na jeden až čtyři bajty a je zajímavé tím, že je kompatibilní s ASCII, UTF-16, které znaky kóduje do dvou nebo čtyř bajtů nebo UCS-4/UTF-32, což jsou shodná kódování přiřazující znakům vždy čtyři bajty.

Unicode je značně univerzální a obsahuje vlastně znaky všech národních abeced (Ameriky, Evropa, Střední Východ, Afrika, Asie a Tichomoří). Pro nás je samozřejmě důležité že i ty naše špecifické - česko - slovenské.

Pro kódování češtiny se používají i jiná kódování: je to především Windows-1250 (používané ve Windows), ISO-8859-2 (dříve zvané Latin2 nebo Latin 2) používané na operačním systému Linux a další. V Javě je samozřejmě možné mezi jednotlivými kódováními převádět.

Unicode a Java

Pokud jste někdy programovali v Javě, určitě jste narazili na problém jak nahnat do svých aplikací, appletů a konfiguračních souborů spoustu všelijakých znaků se všelijak zkroucenými znamínky v záhlaví. Tento problém samozřejmě není neřešitelný a já se jej pokusím teď rozebrat.

V Javě jsou všechny znaky (a taky stringy) reprezentovny právě pomocí Unicode, které se zapisují pomocí escape sekvencí takto

char ch = '\unnnn';
kde nnnn je hexadecimální vyjádření pozice znaku v tabulce Unicode.

Za normálních okolností tento zápis zřejmě nepoužijete, protože překladač si ASCII znaky "konvertuje" sám, problém nastává až s národními (českými) znaky. Tady už tento zápis použít musíte.

Zápis ě (e s háčkem) pomocí escape sekvence v Unicode vypadá

char ch = '\u011B';
Pokud chceme napsat slůvko pěkně použijeme konstrukci
String s = "p" + '\u011B' + "kn" + '\u011B';
Asi si řeknete, že je to poměrně složité, ale odměnou vám je, že takovéto české znaky budou čitelné skutečně na všech platformách. Samozřejmě za předpokladu, že je k dispozici font s odpovídajícími (českými) znaky!

Znaky ve zdrojovém kódu

Novější verze kompilátoru Javy (určitě od verze 1.4) umožňují použití přepínače --encoding kódování, který umožní zapisovat zdrojový kód ve zvoleném kódování, a kompilátor sám provede konverzi do Unicode. Rovněž vývojová prostředí vám dovolí nastavit kódování zdrojového textu, a například Eclipse pro Windows správně samo nastaví kódování na Windows-1250.

Znaky v načítaných souborech

Pokud do Javovského programu potřebujeme načíst soubor, který není kódován v Unicode, s úspěchem využijeme druhý parametr konstruktoru třídy InputStreamReader, kde specifikujeme kódování souboru.

BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream("soubor.txt"), "windows-1250"));

Servlety

V servletech je nutné nastavit vámi používané kódování nejenom pro response, ale i pro request.

request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");

JSP

Ve svých JSP stránkách uvádějte používané kódování pomocí direktivy

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>

Tuto direktivu nezapomeňte vložit i do souborů, které vkládáte pomocí <%@ include file="soubor.html" %>.

Databáze

Většina databází (a databázových driverů), ke kterým se přistupuje přes JDBC, nemá se správným překódováním znaků mezi kódováním databáze a Javou problém (PostgreSQL, Oracle,...), nicméně MySQL vyžaduje použité kódování uvést v connection stringu. Pokud databáze používá kódování Windows 1250, bude to vypadat takto:

jdbc:mysql://hostname/database?characterEncoding=Cp1250

Pro ISO 8859-2 použijeme hodnotu ISO8859_2.

Pokud databáze používá UTF-8, je třeba ještě přidat parametr useUnicode=true:

jdbc:mysql://hostname/database?useUnicode=true&characterEncoding=UTF-8

Oříznutí diakritiky

Občas se hodí dikaritiku z textu odstranit (z č udělat c).

V Javě verze 1.4 a 5 je třída Normalizer, která je součástí nestandardního balíčku sun.text:

String bez = Normalizer.normalize("žluťoučký", Normalizer.DECOMP, 0).replaceAll("[^\\p{ASCII}]","");

V Javě od verze 6 pak je pak přesunuta java.text.Normalizer a má trochu jinou syntaxi:

String bez = Normalizer.normalize("žluťoučký", Form.NFD).replaceAll("[^\\p{ASCII}]","");

Můžeme také použít ICU (International Components for Unicode). (Kompletní ICU4J má přes 3MB, ale samotný jar s transliterátorem má cca 700kB, viz How to modularize ICU4J.)

Transliterator t = Transliterator.getInstance("NFD; [:Nonspacing Mark:] Remove; NFC");
String bez = t.transliterate("žluťoučký");


Tabulky

Do následující tabuldy jsem, dovoluji si říct přehledně, uspořádal české znaky a jim odpovídající hexadecimální Unicode vyjádření.
  Znak     hexa hodnota     Znak     hexa hodnota     Znak     hexa hodnota  
Á00C1 Í00CD Ť0164
á00E1 í00ED ť0165
Č010C Ň0147 Ú00DA
č010D ň0148 ú00FA
Ď010E Ó00D3 Ů016E
ď010F ó00F3 ů016F
É00C9 Ř0158 Ý00DD
é00E9 ř0159 ý00FD
Ě011A Š0160 Ž017D
ě011B š0161 ž017E

A kdo mi nevěří, tak tady jsou dvě originální Unicode tabulky se znaky, které jsou pro nás důležité.
tabulka znaků 0080 - 00FF tabulka znaků 0100 - 017F
Další tabuldy znaků 0180 - 0217 a 2100 - 2138

Šťastné a veselé programování přeje Martiner


Prameny: David Flanagan: Programování v jazyce Java a http://www.unicode.org
Název a loga Unicode jsou nepochybně registrovanými značkami Unicode Consorcium.

Webhosting zajišťuje Macroware s.r.o.