/
charsets-unicode.html.de
473 lines (409 loc) · 20 KB
/
charsets-unicode.html.de
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
[%setvar section Artikel%]
[%setvar title Zeichenkodierungen oder „Warum funktionieren meine Umlaute nicht?”%]
[%menu main artikel unicode %]
[%setvar en /en/article/encodings-and-unicode %]
<!-- INDEX BEGIN -->
<h1 id="charsets_oder_warum_funktionieren_meine_umlaute_nicht">[%readvar title%]</h1>
<p>Dieser Artikel beschreibt die verschiedenen Zeichenkodierungen, wie sie
zu Problemen führen können, und wie man sie in Perl-Programmen korrekt
berücksichtigt.</p>
<h3 id="toc">Inhaltsverzeichnis</h3>
<ul>
<li><a href="#einfuehrung">Einführung</a></li>
<li><a href="#ascii">ASCII</a></li>
<li><a href="#andere_zeichenkodierungen">Andere Zeichenkodierungen</a></li>
<li><a href="#unicode">Unicode</a>
<ul>
<li><a href="#unicode_transformation_formats">Unicode Transformation Formats</a></li>
</ul></li>
<li><a href="#was_sind_charsets">Was sind „Charsets”?</a></li>
<li><a href="#perl_und_zeichenkodierungen">Perl und Zeichenkodierungen</a></li>
<li><a href="#die_arbeitsumgebung_testen">Die Arbeitsumgebung testen</a></li>
<li><a href="#troubleshooting">Troubleshooting</a></li>
<li><a href="#kodierungen_im_www">Kodierungen im WWW</a></li>
<li><a href="#weiterfuehrende_themen">Weiterführende Themen</a></li>
<li><a href="#links">Links</a></li>
</ul>
<!-- INDEX END -->
<h2 id="einfuehrung">Einführung</h2>
<p>Jeder hat es schon mindestens einmal erlebt: Ein Programm, das mit Text
arbeitet, funktioniert wunderbar, solange man keine Umlaute eingibt. Sonst
kommt nur noch Zeichenmüll heraus und ein bis zwei nicht korrekt
dargestellte Zeichen pro Umlaut.</p>
<h2 id="ascii">ASCII</h2>
<p>Um zu verstehen, warum es dazu kommt, muss man sich anschauen, wie
„normaler” Text und wie Umlaute binär abgespeichert werden.</p>
<p>Angefangen hat es 1963 mit ASCII, einem Standard, der 128 Zeichen
je eine Zahl von 0 bis 127 zuweist, die mit 7 bit kodiert werden können.</p>
<p>Festgelegt sind die Zahlenwerte für lateinische Buchstaben, Ziffern, Satzzeichen
und Kontrollzeichen wie „Carriage Return” und „Line Feed”, also
Zeilenumbrüche.</p>
<p>Zeichen, die im Alltag eines Amerikaners nicht vorkommen, wie die deutschen
Umlaute, kyrillische Zeichen und vieles mehr, wurden ausser Acht gelassen.</p>
<p>Da ein Byte aus 8 Bits besteht, ist bei ASCII das erste, „most significant” Bit
immer 0.</p>
<h2 id="andere_zeichenkodierungen">Andere Zeichenkodierungen</h2>
<p>Als man in Europa anfing Computer zu benutzen, mussten die benötigten Zeichen
irgendwie im Computer gespeichert werden und dazu benutzte man die
verbleibenden 128 Zeichen pro Byte. So entstanden die Kodierungen Latin-1 für
den westeuropäischen Raum, Latin-2 für Mitteleuropa und so weiter, auch
bekannt als ISO-8859-1 und ISO-8859-2.</p>
<p>Diese Zeichensätze stimmen in den ersten 128 Zeichen mit ASCII
überein, die zweiten 128 Zeichen, also die mit 1 als erstem Bit,
unterscheiden sich jeweils untereinander.</p>
<p>
Die Grenzen dieser Zeichensätze werden einem schnell anhand eines gar
nicht so alten Beispieles klar: Mit der Einführung des Euros hatten viele
Länder eine neue Währung und damit ein Währungssymbol, das sich nicht in
den traditionellen Zeichensätzen ausdrücken ließ! (Dieses Problem wurde
durch das Einführen des Zeichensatzes ISO-8859-15 behoben, der sich nur
wenig von Latin-1 unterscheidet und das <code>€</code>-Zeichen
enthält).
</p>
<h2 id="unicode">Unicode</h2>
<p>
Die bisherigen Zeichenkodierungen konnten jeweils nur einen kleinen, lokal
sinnvollen Bereich aller möglicher Zeichen darstellen - sobald man Texte mit
gemischten Zeichensätzen verfassen wollte, ging das heillose Chaos los.
</p>
<p>Um etwas Ordnung in das Chaos zu bekommen, hat das Unicode-Konsortium damit
angefangen, jedem Zeichen, das in irgend einer Schrift in irgend einer Sprache
vorkommt, eine eindeutige, ganze Zahl und einen Namen zuzuordnen.</p>
<p>Die Zahl heißt „Codepoint” und wird üblicherweise als vier- oder
sechsstellige, hexadezimale Zahl in der Form <code>U+0041</code> notiert; der
dazugehörige Name wäre <code>LATIN SMALL LETTER A</code>.</p>
<p>Neben Buchstaben und anderen „Basiszeichen” gibt es auch Akzentuierungen wie
den z. B. <code>ACCENT, COMBINING ACUTE</code>, die auf den vorherigen Buchstaben einen
Akzent setzen.</p>
<p>Wenn auf ein Basiszeichen eine Akzentuierung oder andere kombinierende
Zeichen folgen, bilden mehrer Codepoints ein logischen Buchstaben, ein
sogenanntes Grapheme.</p>
<h3 id="unicode_transformation_formats">Unicode Transformation Formats</h3>
<p>Die bisher vorgestellten Unicode-Konzepte stehen vollständig unabhängig davon,
wie die Unicode-Zeichen kodiert werden.</p>
<p>Dafür wurden die „Unicode Transformation Formats” definiert,
Zeichenkodierungen, die alle möglichen Unicode-Zeichen darstellen können. Der
bekannteste Vertreter ist UTF-8, das für die bisher vergebenen Codepoints
1 bis 4 Bytes benötigt.</p>
<p>Auch in UTF-8 stimmen die ersten 128 Zeichen mit denen von ASCII überein.</p>
<p>Von UTF-8 gibt es auch eine laxe Variante, UTF8 (ohne Bindestrich
geschrieben), die mehrere mögliche Kodierungen für ein Zeichen zulässt. Das
Perl-Modul <em>Encode</em> unterscheidet diese Varianten.</p>
<p>UTF-16 dagegen benutzt für jedes Zeichen mindestens zwei Byte, für sehr hohe
Unicode-Codepoints werden auch hier mehr Bytes benötigt.</p>
<p>UTF-32 kodiert jedes mögliche Zeichen mit vier Bytes.</p>
<table summary="Beispiele für Zeichenkodierungen">
<tr>
<th>Codepoint</th><th>Zeichen</th><th>ASCII</th><th>UTF-8</th><th>Latin-1</th><th>ISO-8859-15</th><th>UTF-16</th>
</tr>
<tr>
<td>U+0041</td><td>A</td><td>0x41</td><td>0x41</td><td>0x41</td><td>0x41</td><td>0x00 0x41</td>
</tr>
<tr>
<td>U+00c4 </td><td> Ä </td><td> - </td><td> 0xc3 0x84
</td><td> 0xc4 </td><td> 0xc4 </td><td> 0x00 0xc4</td>
</tr>
<tr>
<td>U+20AC </td><td> € </td><td> - </td><td> 0xe2 0x82 0xac
</td><td> - </td><td> 0xa4 </td><td> 0x20 0xac</td>
</tr>
<tr>
<td>U+c218 </td><td> 수 </td><td> - </td><td> 0xec 0x88 0x98
</td><td> - </td><td> - </td><td> 0xc2 0x18</td>
</tr>
</table>
<p>
(Das Zeichen in der letzten Zeile ist das Hangul-Zeichen für die Silbe
SU, und wird von Ihrem Browser nur dargestellt, wenn Sie entsprechende
asiatische Schriftarten installiert haben.)
</p>
<h2 id="was_sind_charsets">Was sind „Charsets”?</h2>
<p>
Das Wort <em>charset</em> wird mit zwei verschiedenen, zum Teil
widersprüchlichen Bedeutungen verwendet.
</p>
<p>
Es kommt aus dem Englischen, und ist eigentlich eine Abkürzung für
<em>character set</em>. <em>Set</em> ist Englisch für <em>Menge</em>, wenn
man es wörtlich nimmt ist also ein Repertoir von Zeichen gemeint, wie
Unicode eines definiert. Allerdings schränken auch Kodierungen wie ASCII
oder Latin-1 den Zeichensatz ein, stellen also neben Kodierungen auch ein
Repertoire oder charset da.
</p>
<p>
Häufig wird <em>charset</em> auch einfach als Synonym für Zeichenkodierung
benutzt, wie zum Beispiel in den HTTP-Headern, die weiter unten noch
einmal erwähnt werden.
</p>
<h2 id="perl_und_zeichenkodierungen">Perl und Zeichenkodierungen</h2>
<p>
Perl unterscheidet bei Operationen auf Strings zwischen solchen, die
die Strings als Text betrachten (wie z.B. <code>uc</code>,
<code>lc</code> und <code>substr</code> sowie reguläre Ausdrücke),
und solche, die Strings als Binärdaten betrachten, wie etwa
<code>print</code> und das Lesen aus Dateihandles.
</p>
<p>
Damit Perl für die Textoperationen die Strings richtig interpretieren
kann, muss man sie dekodieren. Das kann man mit dem der Funktion
<code>decode</code> in dem Core-Modul <a
href="http://search.cpan.org/perldoc?Encode">Encode</a> machen, oder
mit den unten beschriebenen IO-Layern.
</p>
<p>
Umgekehrt muss man Strings mit <code>Encode::encode</code> kodieren, um binäre
Operationen wie <code>print</code> auszuführen.
</p>
<p>
Alle Textoperationen sollte man auf nur auf Strings ausführen, die vorher
dekodiert wurden, weil dann auch
Nicht-ASCII-Zeichen korrekt behandelt werden: <code>lc</code> und
<code>uc</code> funktionieren wie erwartet, und <code>\w</code> in
regulären Ausdrücken passt auf jeden Buchstaben, auch auf Umlaute,
<code>ß</code> und allen möglichen Zeichen in allen möglichen
Sprachen, die dort als Bestandteil eines Wortes angesehen werden.
</p>
<p>
<code>cmp</code> vergleicht Nicht-ASCII-Zeichen allerdings
nach Unicode-Codepoint, was nicht immer das ist, was man z.B. in
deutschem Text erwartet. Nur wenn <code>use locale</code> aktiv ist,
werden sprachspezifische Vergleichsregeln benutzt.
Da das Verhalten von <code>sort</code> durch <code>cmp</code> definiert
ist, gilt dies auch für das Sortieren von Listen.
</p>
<pre>[%syntax perl%]
#!/usr/bin/perl
use warnings;
use strict;
use Encode qw(encode decode);
my $enc = 'utf-8'; # in dieser Kodierung ist das Script gespeichert
my $byte_str = "Ä\n";
# Bytestrings:
print lc $byte_str; # gibt 'Ä' aus, lc hat nichts verändert
# Textstrings:
my $text_str = decode($enc, $byte_str);
$text_str = lc $text_str;
print encode($enc, $text_str); # gibt 'ä' aus, lc hat gewirkt
[%endsyntax%]</pre>
<p>Es empfiehlt sich, alle Eingaben direkt zu dekodieren, dann mit
diesen Strings zu arbeiten, und sie erst bei der Ausgabe (oder beim
Speichern) wieder in Bytestrings zu kodieren. Wenn man sich nicht an
diese Regel hält, verliert man im Programm schnell den Überblick
welcher String ein bereits dekodiert wurde und welcher nicht.
</p>
<p>
Perl bietet mit den IO-Layern Mechanismen, mit denen man das kodieren und
dekodieren an Dateihandles oder global an allen Handles durchführen lassen
kann.
</p>
<pre>[%syntax perl%]
# IO-Layer: $handle liefert beim Lesen jetzt Textstrings:
open my $handle, '<:encoding(UTF-8)', $datei;
# das Gleiche:
open my $handle, '<', $datei;
binmode $handle, ':encoding(UTF-8)';
# Jedes open() soll automatich :encoding(iso-8859-1) benutzen:
use open ':encoding(iso-8859-1)';
# Alle Stringkonstanten werden als utf-8 interpretiert
# und automatisch dekodiert
use utf8;
# Schreibe Text mit der aktuellen locale nach STDOUT:
use PerlIO::locale;
binmode STDOUT, ':locale';
# alle Lese-/Schreibeoperation mit aktueller locale:
use open ':locale';
[%endsyntax%]</pre>
[% comment make vim happy again: ' %]
<p>
Mit Vorsicht sollte man den Input Layer <code>:utf8</code> genießen,
der annimmt, dass die Eingabedatei gültiges UTF-8 ist.
Sollte sie das nicht sein (und man hat keine Möglichkeit, das zu
überprüfen), ist das eine potentielle Quelle für Sicherheitslücken (siehe
<a href="http://www.perlmonks.org/?node_id=644786">diesen Artikel auf
Perlmonks</a> für Details).
</p>
<p>
Das Modul und Pragma <em>utf8</em> erlaubt es auch, Nicht-ASCII-Zeichen in
Variablennamen zu verwenden. In Namespaces und Modulenamen sollte man
davon absehen, da es dort nicht zuverlässig funktioniert. Auch sollte man
immer beachten, dass nicht jeder die Möglichkeit hat, beliebige
Unicode-Zeichen mit der Tastatur einzugeben.
</p>
<h2 id="die_arbeitsumgebung_testen">Die Arbeitsumgebung testen</h2>
<p>Ausgestattet mit diesem Wissen kann man testen, ob das Terminal und locales
auf die gleiche Kodierung eingestellt sind, und auf welche:</p>
<pre>[%syntax perl%]
#!/usr/bin/perl
use warnings;
use strict;
use Encode;
my @charsets = qw(utf-8 latin1 iso-8859-15 utf-16);
my $test = 'Ue: ' . chr(220) .'; Euro: '. chr(8364) . "\n";
for (@charsets){
print "$_: " . encode($_, $test);
}
[%endsyntax%]</pre>
<p>Wenn man dieses Programm in einem Terminal ausführt, wird nur eine Textzeile
korrekt angezeigt werden, die erste Spalte darin ist dann die Zeichenkodierung
des Terminals.</p>
<p>Wie vorher gesagt ist das Eurozeichen <code>€</code> nicht in Latin-1 vorhanden, das <code>Ü</code>
sollte in einem Latin-1-Terminal trotzdem richtig angezeigt werden.</p>
<p>In Windowsterminals sind auch die Zeichenkodierungen <code>cp850</code> und
<code>cp858</code> (die nur von neuen Encode-Versionen unterstützt wird)
üblich, der Rest der Betriebsumgebung benutzt <code>Windows-1252</code>.</p>
<p>Um den obigen Test auf alle in Perl verfügbaren Zeichenkodierungen
auszuweiten, kann man die Liste der Kodierungen durch
<code>Encode->encodings(':all')</code> ersetzen.</p>
<h2><a id="troubleshooting"></a>Troubleshooting</h2>
<h3 id="wide_character">"Wide Character" - Warnungen</h3>
<p>Manchmal stolpert man über <code>"Wide character in print"</code> und
ähnliche Warnungen. Sie bedeuten, dass ein vorher dekodierter String, der
intern als UTF-8 gespeichert wurde, für eine Operation benutzt wurde,
in der nur binäre Daten sinnvoll sind.</p>
<p>Abhilfe schafft es, den String vorher mit <code>Encode::encode</code>
oder
einem entsprechenden Output-Layer zu kodieren.</p>
<h3 id="strings-untersuchen">Strings Untersuchen</h3>
<p>
Leider dokumentieren viele Module nicht, welche Art von Daten sie
zurückliefert, also ob sie bereits dekodiert wurden oder nicht.
</p>
<p>
Im Allgemeinen ist das auch nicht durch eine Analyse der Strings
herauszufinden, da Perl 5 keine getrennten Datentypen für dekodierte und
für binäre Strings hat.
</p>
<p>
Es gibt aber eine Heuristik, die manchmal hilft. Dazu benötigt man das
Modul
<a href="http://search.cpan.org/perldoc?Devel::Peek">Devel::Peek</a>:
</p>
<pre>[%syntax perl%]
use Devel::Peek;
use Encode;
my $str = "ä";
Dump $str;
$str = decode("utf-8", $str);
Dump $str;
Dump encode('latin1', $str);[%endsyntax%]
__END__
SV = PV(0x814fb00) at 0x814f678
REFCNT = 1
FLAGS = (PADBUSY,PADMY,POK,pPOK)
PV = 0x81654f8 "\303\244"\0
CUR = 2
LEN = 4
SV = PV(0x814fb00) at 0x814f678
REFCNT = 1
FLAGS = (PADBUSY,PADMY,POK,pPOK,UTF8)
PV = 0x817fcf8 "\303\244"\0 [UTF8 "\x{e4}"]
CUR = 2
LEN = 4
SV = PV(0x814fb00) at 0x81b7f94
REFCNT = 1
FLAGS = (TEMP,POK,pPOK)
PV = 0x8203868 "\344"\0
CUR = 1
LEN = 4</pre>
<p>
Der String <code>UTF8</code> in der Zeile <code>FLAGS =</code> zeigt,
dass der String intern als UTF-8 gespeichert wird und bereits dekodiert
wurde. In der Zeile <code>PV =</code> sieht man bei solchen Strings die
Bytes und in eckigen Klammern die Codepoints.
</p>
<p>
Allerdings ist der Umkehrschluss nicht zulässig: das Fehlen des UTF8
Flags bedeutet keineswegs, dass der String vorher nicht dekodiert wurde.
Es bedeutet lediglich, dass perl für Textoperationen die Kodierung Latin-1
annimmt.
</p>
<h3 id="fehlerhafte-module">Fehlerhafte Module</h3>
<p>Weitere Probleme können durch fehlerhafte Module entstehen. So ist die
Funktionalität des Pragmas <em>encoding</em> sehr verlockend:</p>
<pre>[%syntax perl%]
# automatische Konvertierungen:
use encoding ':locale';[%endsyntax%]</pre>
<p>Allerdings funktionieren unter dem Einfluss von <code>use encoding</code>
AUTOLOAD-Funktionen nicht mehr, und das Modul funktioniert nicht im
Zusammenspiel mit Threads.</p>
<h2 id="kodierungen_im_www">Kodierungen im WWW</h2>
<p>Beim Schreiben von CGI-Scripten muss man sich überlegen in welcher Kodierung
die Daten ausgegeben werden sollen und das entsprechend im HTTP-Header
vermerken.</p>
<p>Für die meisten Anwendungen empfiehlt sich UTF-8, da man damit einerseits
beliebge Unicode-Zeichen kodieren kann, andererseits auch deutschen Text
platzsparend darstellen kann.</p>
<p>HTTP bietet zwar mit dem <code>Accept-Charset</code>-Header eine Möglichkeit
herauszufinden, ob ein Browser mit einer Zeichenkodierung etwas anfangen kann,
aber wenn man sich an die gängigen Kodierungen hält, ist es in der Praxis
nicht nötig, diesen Header zu prüfen.</p>
<p>Für HTML-Dateien sieht ein Header typischerweise so aus:
<code>Content-Type: text/html; charset=UTF-8</code>. Wenn man einen solchen Header
sendet, muss man im HTML-Code nur die Zeichen escapen, die in HTML eine
Sonderbedeutung haben (<code><</code>, <code>></code>, <code>&</code> und innerhalb von Attributen
auch <code>"</code>).</p>
<p>
Zu beachten ist auch, dass der HTTP-Header (und damit auch URLs) nur
ASCII-Zeichen enthalten darf, d.h. URLs und Cookies müssen nach ASCII
kodiert werden. Üblich ist es, die Daten in UTF-8 umzuwandeln, und alle
Bytewerte größer als 127 (und solche die dort nicht erlaubt sind, z.B.
Leerzeichen in URLs) als Prozentzeichen gefolgt vom zweistelligen
Hexadezimalwert des Bytes zu kodieren. Aus einem Leerzeichen wird dabei
<code>%20</code>, aus einem Ä wird <code>%c4%84</code>.
</p>
<p>Beim Einlesen von POST- oder GET-Parametern mit dem Modul <em>CGI</em> muss man
darauf achten, welche Version man benutzt: In älteren Versionen liefert die
<code>param</code>-Methode immer Bytestrings zurück, in neueren Versionen (ab 3.29)
werden die Strings dekodiert zurückgegeben, wenn vorher mit
<code>charset</code> die
Zeichenkodierung UTF-8 eingestellt wurde - andere Kodierungen werden von
<em>CGI</em> nicht unterstützt.</p>
<p>Damit Formularinhalte vom Browser mit bekanntem Zeichensatz abgeschickt
werden, gibt man im Formular das <code>accept-charset</code>-Attribut mit an:</p>
<pre>[%syntax html%]
<form method="post" accept-charset="utf-8" action="/script.pl">[%endsyntax%]</pre>
<!-- TODO: fix link-->
<p>
Bei Verwendung eines Template-Systems sollte man darauf achten, dass es
mit Zeichenkodierungen umgehen kann. Beispiele sind <a
href="http://search.cpan.org/perldoc?Template::Alloy">Template::Alloy</a>,
<a href="http://search.cpan.org/perldoc?HTML::Template::Compiled">HTML::Template::Compiled</a>
(seit Version 0.90 mit der Option <code>open_mode</code>) oder
Template Toolkit in Verbindung mit
<a href="http://search.cpan.org/perldoc?Template::Provider::Encoding">Template::Provider::Encoding</a>.
</p>
<h2 id="weiterfuehrende_themen">Weiterführende Themen</h2>
<p>Mit den Grundlagen zu den Themen Zeichenkodierungen und Perl kommt man schon
sehr weit, zum Beispiel kann man Webanwendunen „Unicode-Safe” machen, also
dafür sorgen, dass alle möglichen Zeichen vom Benutzer eingegeben und
dargestellt werden können.</p>
<p>Damit ist aber noch längst nicht alles auf diesem Gebiet gesagt.
Der Unicode-Standard erlaubt es beispielsweise, bestimmte Zeichen auf
verschiedene Arten zu kodieren. Um Strings korrekt miteinander zu vergleichen,
muss man sie vorher „normalisieren”. Mehr dazu gibt es in der
<a
href="http://unicode.org/faq/normalization.html">Unicode-Normalisierungs-FAQ</a>.</p>
<p>Um landesspezifisches Verhalten für Programme zu implementieren, lohnt es, die
locales genauer anzusehen.
Im Türkischen z.B. wird <code>lc 'I'</code> zu
<code>ı, U+0131 LATIN SMALL LETTER DOTLESS I</code>,
während <code>uc 'i'</code> zu <code>İ,
U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE</code> wird..
Ein guter Einstiegspunkt in die Locales ist das Dokument
<!-- TODO: link-->
<em>perllocale</em>.</p>
<h2 id="links">Links</h2>
<ul>
<li><a
href="http://toscho.de/2008/grundlagen-zeichenkodierung/">Grundlagen
der Zeichenkokdierungen ausführlich erklärt</a></li>
<li>Das selfhtml-wiki <a
href="http://wiki.selfhtml.org/wiki/Themen:Zeichencodierung/Webserver">diskutiert
Zeichensatz im Zusammenhang mit HTTP und HTML</a>.</li>
</ul>
<hr />
<p>Dieser Artikel wurde für das <a
href="http://foo-magazin.de/">$foo-Magazin</a> geschrieben und in der 5.
Ausgabe (Anfang 2008) veröffentlicht.</p>
[% comment vim: ft=html spell spelllang=de_de
%]