Myślę, że problem w twoim przypadku nie jest związany z std::wstring :8-bitowy std::string powinno wystarczyć dla UTF-8 (tworzenie prostego std::string ze znakami specjalnymi "āàčīēļš" po prostu działa dobrze), podczas gdy w zależności od systemu operacyjnego std::wstring ma 2 bajty (Windows) lub 4 bajty (Linux) (więcej informacji tutaj
i tutaj
). W końcu, jeśli spojrzysz na getString zobaczysz, że pobiera i zwraca sql::SQLString . sql::SQLString klasa jest prostym opakowaniem dla std::string .
Myślę, że musisz określić utf-8 jako domyślny zestaw znaków dla MySql :W tym celu musisz określić następujące opcje połączenia
podczas łączenia się z bazą danych:
std::unique_ptr<sql::Connection> connection {nullptr};
try {
sql::Driver* driver = ::get_driver_instance();
sql::ConnectOptionsMap connection_options {};
connection_options["hostName"] = url; // Replace with your log-in
connection_options["userName"] = username; // ...
connection_options["password"] = password; // ...
connection_options["schema"] = schema; // ...
connection_options["characterSetResults"] = "utf8";
connection_options["OPT_CHARSET_NAME"] = "utf8";
connection_options["OPT_SET_CHARSET_NAME"] = "utf8";
connection.reset(driver->connect(connection_options));
} catch (sql::SQLException& ex) {
std::cerr << "Error occured when connecting to SQL data base: " << ex.what() << "(" << ex.getErrorCode() << ").";
}
Powinno być możliwe kontynuowanie przeszukiwania bazy danych w następujący sposób
std::string const some_query = "SELECT * FROM some_table_name;";
std::unique_ptr<sql::Statement> statement {connection->createStatement()};
std::unique_ptr<sql::ResultSet> result {statement->executeQuery(some_query)};
while (result->next()) {
std::string const some_field = result->getString("some_field_name");
// Process: e.g. display with std::cout << some_field << std::endl;
}
Problem, który teraz pojawia się, gdy chcesz tworzyć nazwy plików za jego pomocą lub wyprowadzać je do konsoli, to Windows sam (testowałem kod wcześniej tylko z Linuksem i dlatego wcześniej nie napotkałem tego problemu!):Domyślnie używa ANSI, a nie UTF-8. Nawet jeśli wypiszesz coś takiego jak āàčīēļš nie wyświetli go poprawnie bez względu na to, czy używasz std::cout lub std::wcout w połączeniu z std::wstring . Zamiast tego wypisze ─ü├á─ì─½─ô─╝┼í .
Jeśli wyodrębnisz bajty
void dump_bytes(std::string const& str) {
std::cout << std::hex << std::uppercase << std::setfill('0');
for (unsigned char c : str) {
std::cout << std::setw(2) << static_cast<int>(c) << ' ';
}
std::cout << std::dec << std::endl;
return;
}
wyświetli C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1 który podłącza go z powrotem do konwertera bajt-do-utf8, takiego jak ten
w rzeczywistości da ci āàčīēļš . Tak więc ciąg został odczytany poprawnie, ale Windows po prostu nie wyświetla go poprawnie. Poniższe w połączeniu z ostatnią sekcją (określającą utf-8 jako domyślny zestaw znaków w MySql) powinien naprawić wszystkie twoje problemy:
-
Wywołanie
SetConsoleOutputCP(CP_UTF8);zwindows.hna początku programu naprawi wyjście konsoli :#include <cstdlib> #include <iostream> #include <string> #include <windows.h> int main() { // Forces console output to UTF8 SetConsoleOutputCP(CP_UTF8); std::string const name = u8"āàčīēļš"; std::cout << name << std::endl; // Actually outputs āàčīēļš return EXIT_SUCCESS; } -
Podobnie będziesz musiał dostosować swoją rutynę, która tworzy pliki ponieważ domyślnie nie będzie to również UTF8 (zawartość plików nie będzie problemem, ale sama nazwa pliku będzie!). Użyj
std::ofstreamzfstreamw połączeniu zstd::filesystem::u8pathz biblioteki C++17filesystemaby rozwiązać ten problem:#include <cstdlib> #include <filesystem> #include <fstream> #include <string> int main() { std::string const name = u8"āàčīēļš"; std::ofstream f(std::filesystem::u8path(name + ".txt")); // Creates a file āàčīēļš.txt f << name << std::endl; // Writes āàčīēļš to it return EXIT_SUCCESS; }