| UTF-8 ist der meist-verwendete Standard Algorithmus zur Codierung von Unicode-Zeichen mit einzelnen Bytes oder Folgen von 2..3 Bytes. | Auf dieser Seite wird vorgestellt, wie man die Programmiersprache C/C++ zur UTF-8 Codierung und Decodierung verwenden kann. |
Zeichencodes |
PC-Codes für Buchstaben, Ziffern und Sonderzeichen |
UTF
|
Unicode Transformation Format - UTF-8 |
| x | x |
UTF-8 Codierung |
|
Unicodeist ein Standard zur weltweit eindeutigen Codierung einer sehr großen Anzahl verschiedener Zeichen.● Die ersten 16 Bit ~ 65000 Zeichen des Unicode werden von allen gängigen Betriebssystemen und Programmen unterstützt. ● Derzeit ist der Unicode mit 21 Bit festgelegt. Das bietet Platz für 221 = 2097152 ~ 2 Mio mögliche Zeichen, von denen die meisten bereits definiert sind. Die vollen 21 Bit werden allerdings nur von professionellen Systemen unterstützt. ● Es ist realistisch, die zukünftige Erweiterung des Unicode auf 24 oder 32 Bit vorzubereiten. 32 Bit bieten Platz für ~ 4 Milliarden Zeichen - genug für alle Zeichen aller Sprachen aller Völker der Erde... Unicode-Zeichen werden oft als CodePoints bezeichnet und in der Form U+**** mit einem hexadezimalen Code von 2, 4, 6 oder 8 Hex-Ziffern bezeichnet. Alle Unicode-Zeichen lassen sich ohne Umschaltung des Zeichensatzes miteinander mischen. Dabei handelt es sich um echte Zeichen im Sinne von Buchstaben, nicht um Bilder. Beispiele:
•
Alle →
ASCII-Zeichen sind als Teil-Menge U+00..U+7F im
Unicode enthalten.• Alle deutschen Umlaute und die meisten westeuropäischen Sonderzeichen sind als Teil-Menge U+80...U+FF ('Latin-1) im Unicode enthalten. • Slawische, Griechische, Cyrillische, Armenische, Hebräische, Arabische, Georgische... Zeichen sind als Teil-Mengen im Unicode enthalten • Die großen asiatischen Bereiche von indischen, chinesischen, japanischen Zeichen sind als große Teil-Mengen im Unicode enthalten. ♦ Details zum Unicode, mit Live-Darstellung aller derzeit verfügbaren Zeichen |
UTFHeutige IT-Systeme sind (noch immer) in Byte-Einheiten organisiert, und der verfügbare Speicherplatz wächst zwar rasch, erlaubt jedoch nicht die Verwendung von 'Worten' von 4 Byte = 32 Bit für einzelne Zeichen (Worte von 2 Byte = 16 Bit wären zu klein).Man muss deshalb Verfahren anwenden, um die große Zahl von Unicode-Zeichen effizient zu verwalten, d.h. mit möglichst wenig Speicherplatz. Der UTF-8 Algorithmus (Unicode Transmission Format - 8-Bit) bietet einen ausgezeichneten Kompromiss zur Lösung genau dieser Aufgabe: • Die 127 meist-verwendeten ASCII-Zeichen werden mit nur 1 Byte codiert. • Die nächste Gruppe von 1920 Zeichen umfasst alle wichtigen europäischen, amerikanischen und arabischen Sprachen. Diese Unicode-Zeichen werden mit je 2 Byte UTF-8 codiert. Dazu gehören auch die 7 deutschen Sonderzeichen (ÄÖÜäöüß). • Die nächste Gruppe von 63488 Zeichen wird mit je 3 Byte UTF-8 codiert. Dazu gehört lediglich das €-Zeichen und einige seltene Sonderzeichen (mathematische Symbole) Insgesamt codiert der UTF-8 Algorithmus alle in Europa verwendeten Zeichen mit nur wenig mehr als 1 Byte pro Zeichen, bietet dafür jedoch einige Vorteile: • UTF-8 codierte Texte sind weltweit eindeutig: Alle Betriebssysteme, alle Programme in allen Ländern stellen diese Zeichen korrekt dar. Man muss dazu keine spezielle Software laden, die Grundausrüstung aller modernen PC ist ausreichend. • Man kann in einem Text alle Unicode-Zeichen verwenden und ohne weitere Maßnahmen miteinander mischen. Bei Verwendung seltener Zeichen vergrößert man damit zwar den Platzbedarf, jedoch weit weniger als durch das Laden vieler nationaler Zeichensätze und das laufende Umschalten zwischen ihnen. |
| x | x |
| x | x |
| x | x |
UTF-8 Codierung |
|
| x | x |
| x | x |
| x | x |
|
Das Beispiel für die
→ Programmiersprache C/C++ arbeitet etwas abweichend von den
übrigen Beispielen, weil Strings in C/C++ anders verwendet werden: ► Das Demo-Programm main() erzeugt eine Text-Datei utf_test.txt mit 3 Zeilen UTF-8 Text. Diese Datei wird mit allen gängigen Text-Editor-Programmen korrekt angezeigt. • Mit der ersten fprintf() Anweisung wird das ↑ BOM eingetragen. • In die 1. Zeile werden die beiden Standard ASCII-Zeichen AZ geschrieben. Der String str wird dazu gelöscht und die Bytes einzeln mit Funktion int_to_utf8() codiert. Das Ergebnis wird im String str gesammelt und zuletzt mit fprintf() ausgegeben. • In der 2. Zeile werden die beiden deutschen Umlaute ÄÜ mit je 2 Byte UTF-8 codiert. Sie können den String str auch durch beliebige andere Maßnahmen ergänzen. • In der 3. Zeile werden die griechischen Zeichen αω mit je 2 Byte und das €-Zeichen mit 3 Byte UTF-8 codiert. ► Funktion int_to_utf8() erwartet als Argumente einen String-Pointer (zur Aufnahme des Ergebnisses) und eine ganze Zahl (den zu verarbeitenden Unicode). Die Funktion gibt die Anzahl der nach Codierung im String enthaltenen Bytes zurück. • Abweichend von den Beispielen anderer Programmiersprachen wird der erzeugte Code an einen bereits bestehenden String angefügt, welcher als Speicher dient und eine beliebige Anzahl von Bytes aufnehmen kann. Der String wird vom aufrufenden Programm als Pointer übergeben und muss von diesem ausreichend dimensioniert werden. • Die UTF-8 Codierung folgt dem gleichen Algorithmus wie die übrigen Beispiele. • Die Funktion fügt nach dem UTF-8 Code ein 0-Byte ein. Der String ist daher nach jeder Anwendung der Funktion zur Ausgabe bereit. |
C/C++ Programm-Beispiel zum Schreiben einer UTF-8 Text-Datei:
#include <stdio.h>
#include <string.h> int int_to_utf8(char*,unsigned int); int main() {
char path[80],str[80];
}FILE *fhw; strcpy(path,"/home/ich/utf_test.txt");
// strcpy(path,"C:\\Daten\\utf_test.txt");
fhw = fopen(path,"w");fprintf(fhw,"\xEF\xBB\xBF"); // BOM str[0]=0; int_to_utf8(str,65); // A int_to_utf8(str,90); // Z fprintf(fhw,"%s\n",str); str[0]=0; int_to_utf8(str,0xC4); // Ae int_to_utf8(str,0xDC); // Ue fprintf(fhw,"%s\n",str); str[0]=0; int_to_utf8(str,0x3B1); // alpha int_to_utf8(str,0x20AC); // euro int_to_utf8(str,0x3C9); // omega fprintf(fhw,"%s\n",str); fclose(fhw); return 0; int int_to_utf8(char *t,unsigned int iuc) {
unsigned int ilen;
} ilen = strlen(t); if(iuc<128) { t[ilen++] = iuc;
}else if(iuc<2048) {
t[ilen++] = (iuc>>6) | 192;
}t[ilen++] = (iuc&63) | 128; else{
t[ilen++] = (iuc>>12) | 224;
}t[ilen++] = ((iuc>>6) & 63) | 128; t[ilen++] = (iuc & 63) | 128; t[ilen] = 0; return ilen; |
UTF-8 Decodierung |
|
|
Das Beispiel für die
→ Programmiersprache C/C++ arbeitet etwas abweichend von den
übrigen Beispielen, weil Strings in C/C++ anders verwendet werden: • Demo-Programm main() Eine UTF-8 Text-Datei utf_test.txt wird geöffnet und wie üblich zeilenweise gelesen. Das Programm muss seine Funktion danach richten, was mit dem decodierten Text geschehen soll. In diesem Beispiel wird der Text zu einer ganzen Zahl (Unicode) decodiert, anschließend als → XML-Entity codiert und ausgegeben. • (Nur) In der 1. Zeile wird mit Funktion check_bom() geprüft, ob ein BOM eingetragen ist, und dieses allenfalls entfernt. • Danach wird der UTF-8 Text jeder Zeile in der String-Variablen str gelesen und an Funktion utf8_decode() übergeben. Das Ergebnis (Anzahl der Ergebnis-Zeichen) wird nach der Zeilen-Nummer ausgegeben. • Anschließend wird der decodierte → XML- bzw. → HTML-konforme Text ausgegeben. ► Funktion check_bom() erhält den Text einer Zeile als String-Pointer. • Sie gibt eine ganze Zahl [0,1] zurück, je nachdem, ob das BOM gefunden wurde oder nicht. • Ein vorhandenes BOM wird aus dem String entfernt, damit dieser weiter decodiert werden kann. ► Funktion utf8_decode() decodiert einen UTF-8 codierten String, der als Pointer übergeben wird. Das decodoerte Ergebnis wird als XML-konformer Text in den gleichen String eingetragen, eine ganze Zahl mit der Länge des Ergebnis-Strings in Byte wird zurückgegeben. • Der erhaltene String s wird in den lokalen String-Buffer t kopiert und dort aufgearbeitet. • Die Ergebnis-Bytes werden schrittweise in den String s eingetragen, der neu aufgebaut und zuletzt mit einem 0-Byte abgeschlossen wird. • Der Algorithmus zur UTF-8 Decodierung folgt den übrigen Beispielen dieser Seite. Je nach Bedarf werden 1..3 Bytes an die Variablen ic0, ic1, ic2 übergeben. • Einzelne ASCII-Bytes werden direkt ausgegeben. • 2 oder 3 UTF8-Bytes werden in der Variablen iuc decodiert. ■ An dieser Stelle kann man die Funktion ändern, um den fertig decodierten Unicode iuc (rot hervorgehoben) beliebig zu verwenden. Im Beispiel wird der Unicode mit der → Standard-Funktion sprintf() in einen → XML-Entity String umgewandelt, an den lokalen String-Buffer h übergeben und mit Standard-Funktion strcat() an den Ergebnis-String s angehängt. Dabei wird auch das abschließende 0-Byte eingetragen. • Die while-Schleife wird abgebrochen, wenn im Eingangs-String ein 0-Byte gefunden wird (ic0==0). Zur Sicherheit wird die Schleife spätestens nach 100 Bytes abgebrochen. Setzen sie diese Grenze und die Größe des Buffer-Strings zur praktischen Anwendung hinauf. • Nach erfolgter Decodierung wird die aktuelle Länge des Ergebnis-Strings s an die Variable j zugewiesen. Ihr Wert-1 wird zuletzt als Gesamt-Länge des Ergebnis-Strings an das aufrufende Programm zurückgegeben. |
C/C++ Programm-Beispiel zum Lesen einer UTF-8 Text-Datei:
#include <stdio.h>
#include <string.h> int check_bom(char*); int utf8_decode(char*); int main() {
int ilen,iline;
}char path[80],str[80]; FILE *fhr; strcpy(path,"/home/ich/utf_test.txt");
// strcpy(path,"C:\\Daten\\utf_test.txt");
fhr=fopen(path,"r");iline=0; while (!feof(fhr)) {
str[0]=0;
}fgets(str,sizeof(str),fhr); if(!iline) {
if(check_bom(str)) {printf("# BOM #\n");}
}ilen=utf8_decode(str); printf("[line %d]: str[len=%d] = %s",iline++,ilen,str); fclose(fhr); return 0; int check_bom(char *t) {
int i;
}unsigned int ic; i=0; if((t[0]&0xFF)==0xEF && (t[1]&0xFF)==0xBB && (t[2]&0xFF)==0xBF) {
while(i<1000) {
}
ic=t[i+3]&0xFF;
}t[i]=ic; if(!ic) {i=9999;} i++; i=1; return i; int utf8_decode(char *s) {
unsigned int i,ic0,ic1,ic2,j,iuc;
}
char t[100],h[10]; strcpy(t,s); i=j=0; s[0]=0; while(i<100) {
ic0=t[i++]&0xFF;
}if(ic0<128) { // iuc=ic0;
s[j++]=ic0; // 1-Byte ASCIIs[j]=0; else{
if(ic0<192) { // Fehler
}
s[j++]=(int)"?";
}s[j]=0; else{
ic1=t[i++] & 0xFF;
}
if(ic0<224) { // 2 Byte
iuc=((ic0&31)<<6) | (ic1&63);
}sprintf(h,"&#x%X;",iuc); strcat(s,h); j=strlen(s); else if(ic0<240) { // 3 Byte
ic2=t[i++] & 0xFF;
}iuc=((ic0&15)<<12) | ((ic1&63)<<6) | (ic2&63); sprintf(h,"&#x%X;",iuc); strcat(s,h); j=strlen(s); else{ // Fehler
s[j++]=(int)"?";
}
s[j]=0; if(!ic0) {i=9999;} return j-1; |
|
Wenn man mit diesem C-Programm die vom oben (Codierung)
gezeigten C-Programm hergestellte UTF-8 Text-Datei analysiert, dann
erhält man diese Ausgabe:
# BOM #
[line 0]: str[len=3] = AZ [line 1]: str[len=13] = ÄÜ [line 2]: str[len=23] = α€ω Sie sind eingeladen, mit den Beispielen zu experimentieren und damit Texte mit beliebigen → Unicode-Zeichen zu codieren und zu decodieren. |
Wenn man die decodierten und als XML-Strings neuerlich codierten Strings in ein XML-Dokument oder in eine HTMl-Webseite einsetzt, dann erhält man das korrekte Ergebnis
# BOM # [line 0]: str[len=3] = AZ [line 1]: str[len=13] = ÄÜ [line 2]: str[len=23] = α€ω Die als Zwischen-Produkt erzeugte Text-Datei wird mit allen modernen Text-Editor-Programmen korrekt angezeigt, z.B. (auf Windows) mit Notepad++. |
|
|