Jag tror att problemet i ditt fall inte är relaterat till std::wstring
:8-bitars std::string
bör vara tillräckligt för UTF-8 (att skapa en enkel std::string
med specialtecknen "āàčīēļš"
fungerar bara bra), medan det beror på operativsystemet std::wstring
är 2 byte (Windows) eller 4 byte (Linux) (mer information här
och här
). När allt kommer omkring om du tittar på getString
funktion kommer du att se att den tar och returnerar en sql::SQLString
. sql::SQLString
klass är bara ett enkelt omslag för en std::string
.
Jag tror att du måste specificera utf-8
som standardteckenuppsättning för MySql :För detta måste du ange följande anslutningsalternativ
när du ansluter till databasen:
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() << ").";
}
Då bör du kunna fortsätta att fråga din databas enligt följande
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;
}
Problemet som nu uppstår när du vill skapa filnamn med den eller mata ut den till konsolen är Windows själv (jag hade testat koden tidigare med endast Linux och stötte därför inte på det här problemet tidigare!):Som standard använder den ANSI och inte UTF-8. Även om du matar ut något som āàčīēļš
det kommer inte att mata ut det korrekt oavsett om du använder en std::cout
eller std::wcout
i kombination med std::wstring
. Istället kommer den att mata ut ─ü├á─ì─½─ô─╝┼í
.
Om du extraherar byte
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;
}
den kommer att mata ut C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1
som kopplar tillbaka den till en byte-till-utf8-omvandlare som denna
ger dig faktiskt āàčīēļš
. Så strängen lästes korrekt men Windows visar den inte korrekt. Följande i kombination med det sista avsnittet (specificerar utf-8
som standardteckenuppsättning i MySql) bör lösa alla dina problem:
-
Ett anrop till
SetConsoleOutputCP(CP_UTF8);
frånwindows.h
i början av programmet fixar konsolutgången :#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; }
-
På samma sätt måste du anpassa din rutin som skapar filerna som standard kommer det inte att vara UTF8 också (innehållet i filerna kommer inte att vara ett problem men själva filnamnet kommer att vara det!). Använd
std::ofstream
frånfstream
i kombination medstd::filesystem::u8path
från C++17-biblioteketfilesystem
för att lösa detta:#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; }