Sie betrachten eine ältere Version der ionflux.org website! Bitte besuchen Sie die neue Version
hier.
UTF-8 Kodierung/Dekodierung (C++)
UTF-8 ist eine Zeichenkodierung, die eine unglaubliche Menge an Zeichen (den
gesamten Unicode-Zeichensatz) unterstützt und es erlaubt, Texte in nahezu jeder
Schrift der Welt zu schreiben und zu übertragen - ohne dabei zu ineffizient zu
sein. UTF-8 ist dabei die Standardkodierung auf Computern und in Netzwerken zu
werden. Hier [externer Link]
bekommen Sie genauere Informationen darüber, was UTF-8 ist und wie es
funktioniert. Die Codeschnipsel in dieser Sektion bieten Kodierung/Dekodierung
von UTF-8 Zeichenketten und verschiedene Hilfsfunktionen.
Jedes Zeichen im Unicode-Zeichensatz wird durch einen numerischen Wert
identifiziert. UTF-8 Zeichenketten sind sind Ketten von Bytes, wobei ein Zeichen
durch ein oder mehrere Bytes repräsentiert wird, je nachdem welchen numerischen
Wert es hat. Für den Zweck dieses Quellcodes werden dekodierte Unicode-Zeichen
als vorzeichenlose Ganzzahlen repräsentiert, während kodierte UTF-8-Zeichen
einfach Standard-C++ Zeichenketten sind.
Kodierer für einzelne Zeichen
Der folgende Quellcode konvertiert ein einzelnes Unicode Zeichen zur
zugehörigen UTF-8 Zeichenkette. Dies ist vielleicht nicht so schön, aber
trotzdem notwendig. ;-)
#include <iostream>
#include <string>
std::string uint_to_utf8(unsigned int uniChar)
{
std::string result;
if (uniChar < 128U)
result.append(1, static_cast<unsigned char>(uniChar));
else
if (uniChar < 2048U)
{
result.append(1, static_cast<unsigned char>((uniChar >> 6) | 0xc0));
result.append(1, static_cast<unsigned char>((uniChar & 0x3f) | 0x80));
} else
if (uniChar < 65536U)
{
result.append(1, static_cast<unsigned char>((uniChar >> 12) | 0xe0));
result.append(1, static_cast<unsigned char>(((uniChar >> 6) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>((uniChar & 0x3f) | 0x80));
} else
if (uniChar < 2097152U)
{
result.append(1, static_cast<unsigned char>((uniChar >> 18) | 0xf0));
result.append(1, static_cast<unsigned char>(((uniChar >> 12) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>(((uniChar >> 6) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>((uniChar & 0x3f) | 0x80));
} else
if (uniChar < 67108864U)
{
result.append(1, static_cast<unsigned char>((uniChar >> 24) | 0xf8));
result.append(1, static_cast<unsigned char>(((uniChar >> 18) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>(((uniChar >> 12) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>(((uniChar >> 6) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>((uniChar & 0x3f)
| 0x80));
} else
if (uniChar < 2147483648U)
{
result.append(1, static_cast<unsigned char>((uniChar >> 30) | 0xfc));
result.append(1, static_cast<unsigned char>(((uniChar >> 24) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>(((uniChar >> 18) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>(((uniChar >> 12) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>(((uniChar >> 6) & 0x3f)
| 0x80));
result.append(1, static_cast<unsigned char>((uniChar & 0x3f) | 0x80));
} else
std::cerr << "[uint_to_utf8] WARNING: Character not representable by UTF-8."
<< std::endl;
return result;
}
Dekodierer für einzelne Zeichen
Der folgende Quellcode dekodiert das erste Unicode-Zeichen in einer UTF-8
Zeichenkette.
#include <iostream>
#include <string>
bool utf8_to_uint(const std::string& bytes, unsigned int& target)
{
unsigned int size = bytes.size();
target = 0;
bool result = true;
if (size == 1)
{
if ((bytes[0] >> 7) != 0)
{
// ----- WARNING ----- //
std::cerr << "[utf8_to_uint] WARNING: Invalid single-byte character."
<< std::endl;
// ----- WARNING ----- */
result = false;
} else
target = bytes[0];
} else
{
unsigned char byte = bytes[0];
target = ((byte & (0xff >> (size + 1))) << (6 * (size - 1)));
unsigned int i = 1;
while (result && (i < size))
{
byte = bytes[i];
if ((byte >> 6) != 2)
{
// ----- WARNING ----- //
std::cerr << "[utf8_to_uint] WARNING: Invalid byte ("
<< static_cast<unsigned int>(byte)
<< ") in UTF-8 sequence at position " << i << "."
<< std::endl;
// ----- WARNING ----- */
result = false;
} else
target |= ((byte & 0x3f) << (6 * (size - 1 - i)));
i++;
}
}
return result;
}
Kodierer für Zeichenketten
Dieser Schnipsel kann verwendet werden, um eine ganze Zeichenkette von
Unicode-Zeichen, angegeben als Vektor von numerischen Code-Werten, in eine UTF-8
Zeichenkette umzuwandeln. Dabei ist eigentlich nichts Besonderes - der Code ruft
einfach die Version von uint_to_utf8() für einzelne Zeichen mehrmals auf.
#include <string>
#include <vector>
void uint_to_utf8(const std::vector<unsigned int>& uniChars,
std::string& target)
{
target = "";
for (unsigned int i = 0; i < uniChars.size(); i++)
target.append(uint_to_utf8(uniChars[i]));
}
Dekodierer für Zeichenketten
Hier ist nun der Dekodierer für UTF-8 Zeichenketten, der eine
Standard-Zeichenkette von der UTF-8 Kodierung in einen Vektor von numerischen
Unicode-Werten umwandelt. Diese Funktion benötigt noch weiteren Quellcode, der
die Länge eines UTF-8 Zeichens berechnet. Dies ist notwendig, da ein Zeichen
mehr als ein Byte benötigen kann, um in der UTF-8 Kodierung dargestellt werden
zu können.
#include <string>
#include <vector>
unsigned int utf8_get_size(unsigned char byte)
{
if (byte < 128)
return 1;
else
if ((byte & 0xe0) == 0xc0)
return 2;
else
if ((byte & 0xf0) == 0xe0)
return 3;
else
if ((byte & 0xf8) == 0xf0)
return 4;
else
if ((byte & 0xfc) == 0xf8)
return 5;
else
if ((byte & 0xfe) == 0xfc)
return 6;
// ----- WARNING ----- //
std::cerr << "[utf8_get_size] WARNING: Invalid character size."
<< std::endl;
// ----- WARNING ----- */
return 0;
}
bool utf8_to_uint(const std::string& bytes, std::vector<unsigned int>& target)
{
unsigned int size = bytes.size();
unsigned int i = 0;
unsigned int charSize = 0;
unsigned int currentChar = 0;
bool result = true;
target.clear();
while (result && (i < size))
{
charSize = utf8_get_size(bytes[i]);
if ((charSize > 0)
&& ((i + charSize) <= size)
&& utf8_to_uint(bytes.substr(i, charSize), currentChar))
i += charSize;
else
{
// ----- WARNING ----- //
std::cerr << "[utf8_to_uint] WARNING: Could not convert UTF-8 character "
"(size = " << charSize << ", position = " << i << ")."
<< std::endl;
// ----- WARNING ----- */
result = false;
}
if (result)
target.push_back(currentChar);
}
return result;
}
Länge einer UTF-8 Zeichenkette
Es mag Fälle geben, in denen es wünschenswert ist, die Länge einer UTF-8
Zeichenkette in Zeichen (nicht Bytes) zu kennen. Dies ist leider nicht möglich,
ohne die gesamte Zeichenkette zu lesen - außer man berechnet die Länge beim
Erstellen der Zeichenkette und speichert sie dann zusammen mit den kodierten
Daten - aber das wäre geschummelt. Hier ist also eine Funktion, die die Länge
der UTF-8 Zeichenkette berechnet, ohne sie tatsächlich zu dekodieren.
#include <string>
unsigned int utf8_get_size(const std::string& bytes)
{
unsigned int size = bytes.size();
unsigned int i = 0;
unsigned int charLen = 0;
unsigned int result = 0;
bool error = false;
while (!error && (i < size))
{
charLen = utf8_get_size(bytes[i]);
if (charLen > 0)
{
result++;
i += charLen;
} else
error = true;
}
if (error)
return 0;
return result;
}