Die Problemdefinition besagt ausdrücklich, dass die 8-Bit-Zeichencodierung UTF-8 ist. Das macht dies zu einem trivialen Problem. Für die Konvertierung von einer UTF-Spezifikation in eine andere ist lediglich ein wenig Aufwand erforderlich.
Schauen Sie sich einfach die Codierungen auf diesen Wikipedia-Seiten für UTF-8 , UTF-16 und UTF-32 an .
Das Prinzip ist einfach: Gehen Sie die Eingabe durch und setzen Sie einen 32-Bit-Unicode-Codepunkt gemäß einer UTF-Spezifikation zusammen. Geben Sie dann den Codepunkt gemäß der anderen Spezifikation aus. Die einzelnen Codepunkte benötigen keine Übersetzung, wie dies bei jeder anderen Zeichenkodierung erforderlich wäre. Das macht dies zu einem einfachen Problem.
Hier ist eine schnelle Implementierung der wchar_t
UTF-8-Konvertierung und umgekehrt. Es wird davon ausgegangen, dass die Eingabe bereits ordnungsgemäß codiert ist - hier gilt das alte Sprichwort "Müll rein, Müll raus". Ich glaube, dass die Überprüfung der Codierung am besten als separater Schritt erfolgt.
std::string wchar_to_UTF8(const wchar_t * in)
{
std::string out;
unsigned int codepoint = 0;
for (in; *in != 0; ++in)
{
if (*in >= 0xd800 && *in <= 0xdbff)
codepoint = ((*in - 0xd800) << 10) + 0x10000;
else
{
if (*in >= 0xdc00 && *in <= 0xdfff)
codepoint |= *in - 0xdc00;
else
codepoint = *in;
if (codepoint <= 0x7f)
out.append(1, static_cast<char>(codepoint));
else if (codepoint <= 0x7ff)
{
out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else if (codepoint <= 0xffff)
{
out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
else
{
out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f)));
out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f)));
out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f)));
}
codepoint = 0;
}
}
return out;
}
Der obige Code funktioniert sowohl für UTF-16- als auch für UTF-32-Eingaben, einfach weil der Bereich d800
durch dfff
ungültige Codepunkte ist. Sie zeigen an, dass Sie UTF-16 dekodieren. Wenn Sie wissen, dass dies wchar_t
32 Bit sind, können Sie Code entfernen, um die Funktion zu optimieren.
std::wstring UTF8_to_wchar(const char * in)
{
std::wstring out;
unsigned int codepoint;
while (*in != 0)
{
unsigned char ch = static_cast<unsigned char>(*in);
if (ch <= 0x7f)
codepoint = ch;
else if (ch <= 0xbf)
codepoint = (codepoint << 6) | (ch & 0x3f);
else if (ch <= 0xdf)
codepoint = ch & 0x1f;
else if (ch <= 0xef)
codepoint = ch & 0x0f;
else
codepoint = ch & 0x07;
++in;
if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
{
if (sizeof(wchar_t) > 2)
out.append(1, static_cast<wchar_t>(codepoint));
else if (codepoint > 0xffff)
{
out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10)));
out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff)));
}
else if (codepoint < 0xd800 || codepoint >= 0xe000)
out.append(1, static_cast<wchar_t>(codepoint));
}
}
return out;
}
Wenn Sie wissen, dass dies wchar_t
32 Bit sind, können Sie Code aus dieser Funktion entfernen, aber in diesem Fall sollte dies keinen Unterschied machen. Der Ausdruck sizeof(wchar_t) > 2
ist zur Kompilierungszeit bekannt, sodass jeder anständige Compiler toten Code erkennt und entfernt.