001
06.05.2011, 23:58 Uhr
0xdeadbeef
Gott (Operator)
|
Strings in C++ sind einfache Byte-Strings. Wenn dieser UTF-8-kodierten Text enthält, wird der ganz normal behandelt. Beispiel:
C++: |
#include <iostream>
int main() { std::cout << "Wenn F\xc3\xa4hrmann Hermann F\xc3\xa4hre f\xc3\xa4hrt," "f\xc3\xa4hrt F\xc3\xa4hrmann Herrmann F\xc3\xa4hre.\n"; }
|
Jetzt ist diese Art der Umschrift natürlich ziemlich umständlich. Wenn es dir nur um die Ausgabe von String-Konstanten geht, ist die einfachste Methode, den Text ganz gehabt hinzuschreiben und den Code in UTF-8 zu speichern - dann wir der Compiler die in UTF-8 kodierten String-Konstanten 1:1 übernehmen.
Wenn ich das richtig lese, kriegst du aber Eingabedaten aus dem Netz und musst diese konvertieren. Glücklicherweise gibt es dazu in POSIX eine Schnittstelle: iconv.
Das funktioniert wie folgt (zunächst nacktes C):
C++: |
#include <iconv.h>
#include <stdio.h> #include <string.h>
int main(void) { char in[] = "Wenn Fährmann Hermann...", out[100]; char *pin, *pout; size_t in_n, out_n; iconv_t convert;
size_t test;
pin = in; pout = out;
out_n = 100; in_n = strlen(in) + 1;
convert = iconv_open("UTF-8", "ISO-8859-15");
test = iconv(convert, &pin , & in_n, &pout, &out_n);
iconv_close(convert);
puts(out);
printf("%d\n", test);
return 0; }
|
Ich hab das hier noch schön in C++ verpackt rumliegen:
C++: |
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #include <iconv.h>
#include <cerrno> #include <cstddef> #include <iostream> #include <string> #include <stdexcept> #include <vector>
struct iconv_error : public std::logic_error { iconv_error(std::string const &message) : std::logic_error(message) { } };
struct iconv_open_error : public iconv_error { iconv_open_error(std::string const &tocode, std::string const &fromcode) : iconv_error("iconv_open fehlgeschlagen: Umwandlung von " + fromcode + " nach " + tocode + "nicht möglich") { } };
class iconverter { public: iconverter(std::string const &tocode, std::string const &fromcode) : converter_(iconv_open(tocode.c_str(), fromcode.c_str())) { if(converter_ == iconv_t(-1)) { throw iconv_open_error(tocode, fromcode); } }
std::string operator()(std::string const &text) { std::size_t n_in = text.size() + 1, n_out = text.size() + text.size() / 5 + 1; // Grobe Abschätzung std::vector<char> outbuffer(n_out); std::vector<char> inbuffer; char *p_in, *p_out; size_t n_converted;
inbuffer.reserve(n_in); inbuffer.assign(text.begin(), text.end()); inbuffer.push_back('\0');
p_in = & inbuffer[0]; p_out = &outbuffer[0];
for(;;) { errno = 0; n_converted = iconv(converter_, &p_in , &n_in, &p_out, &n_out);
if(n_converted != size_t(-1)) { break; } else if(errno == E2BIG) { size_t n_out_old = p_out - &outbuffer[0]; n_out += outbuffer.size(); outbuffer.resize(outbuffer.size() * 2); p_out = &outbuffer[n_out_old]; } else if(errno == EILSEQ) { throw iconv_error("Ungültige Multibyte-Sequenz in Eingabe"); } else if(errno == EINVAL) { throw iconv_error("Unvollständige Multibyte-Sequenz in Eingabe"); } else { throw iconv_error("Unbekannter Umwandlungsfehler"); } }
return std::string(outbuffer.begin(), outbuffer.begin() + outbuffer.size() - n_out - 1); }
~iconverter() { iconv_close(converter_); } private: iconv_t converter_; };
int main() { iconverter utf8_convert("UTF-8", "ISO-8859-15"); std::cout << '"' << utf8_convert("ÄÖÜäöü߀") << '"' << std::endl; }
|
Natürlich musst du den fromcode für deine Eingabedaten passend setzen. Die Implementation ist nicht besonders performant, aber wenn das ein Problem ist, darfst du das selbst richten. -- Einfachheit ist Voraussetzung für Zuverlässigkeit. -- Edsger Wybe Dijkstra Dieser Post wurde am 07.05.2011 um 00:02 Uhr von 0xdeadbeef editiert. |