ANSI nach UTF-8 umwandeln
-
Hallo,
ich habe eine Textdatei, die in ANSI-Codierung gespeichert wurde. Wie kann ich die eingelesenen Strings nach UTF-8 umwandeln oder es gleich beim Lesen aus dem Stream umwandeln lassen? Ich habe mir die <locale> Bibliothek zwar schon angesehen aber irgendwie werde ich nicht so richtig schlau, was ich wo und wie einstellen/angeben muss damit es umgewandelt wird, falls es überhaupt geht.
-
Unter Windows kannst du dafür die beiden Funktionen MultiByteToWideChar und WideCharToMultiByte benutzen, s. z.B. http://www.chilkatsoft.com/p/p_348.asp (auch wenn der Code nicht sonderlich schön ist).
Die Konvertierung ist dabei: ANSI (Windows-1252) -> UNICODE -> UTF-8
-
Habe kein Windows, sondern Debian/Linux.
Trotzdem Danke schön.
-
Willst du das wirklich selber schreiben? Gerade unter Linux gibt es doch das tolle iconv. In Zusammenhang mit finds Fähigkeit, sogar nach Zeichenkodierungen suchen zu können, könnte man damit vollautomatisch ganze Orderstrukturen umwandeln.
Oder geht es um eigene Übung? Dann wäre doch der Anfang der Übung, sich erst einmal mit diesen Formaten zu befassen, dann sollte ein Umwandlungsalgorithmus sich ganz von alleine ergeben.
-
Nein, nein, ich will nichts in der Richtung selber schreiben. Ich hoffte es gibt in der Standardbibliothek oder einer anderen irgendwie eine Funktion mit der man einen String umwandeln lassen kann. Iconv kannte bisher nur als Konsolenbefehl und mit system() wollte ich im Programm nicht so gerne arbeiten. Habe während der Suche nebenbei gesehen, dass es davon eine C-Bibliothek/Funktion gibt. Gibt es von iconv auch ein C++ Äquivalent?
-
Ui, da hab ich passenden Code für rumliegen:
#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, double expansion_hint = 1.2) : converter_ (iconv_open(tocode .c_str(), fromcode.c_str())), expansion_hint_(expansion_hint) { 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; std::size_t n_out = static_cast<std::size_t>(text.size() * expansion_hint_) + 1; // Grobe Abschätzung der Ausgabelänge 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_; double expansion_hint_; }; int main() { iconverter utf8_convert("UTF-8", "ISO-8859-15"); std::cout << '"' << utf8_convert("foo bar") << '"' << std::endl; std::cout << '"' << utf8_convert("ÄÖÜäöüߤ") << '"' << std::endl; }
-
Verdammt, SeppJ war schneller ^^".
Die iconv Funktionen gelten als Unix-Variante zu den genannten Windows-Konvertern, damit würdest du also am besten fahren. Mit codecvt würdest du dagegen plattformunabhängig vorgehen.
-
Hättest du vielleicht ein Beispiel mit codecvt für mich? Wie ich am Anfang schon anmerkte, werde ich aus den Beispielen bei cppreference.com nicht ganz schlau.
-
stefkowa schrieb:
Hättest du vielleicht ein Beispiel mit codecvt für mich? Wie ich am Anfang schon anmerkte, werde ich aus den Beispielen bei cppreference.com nicht ganz schlau.
Das Problem ist nicht cppreference, sondern codecvt. Das kann nur Standardkonvertierungen vom Unicodezeichensatz (UTF-8, UTF-16 (wäh) und UTF-32-Encoding, dazu noch das broken UCS-2).
Für brauchbare Umwandler empfehle ich www.boost.org/libs/locale/doc/html/charset_handling.html
-
boost::locale mit to_utf ist genau das, was ich gesucht habe. Funktioniert einwandfrei und lässt sich einfach anwenden.
DANKE!