Мисля, че проблемът във вашия случай не е свързан с std::wstring
:8-битовият std::string
трябва да е достатъчно за UTF-8 (създаване на прост std::string
със специалните знаци "āàčīēļš"
просто работи добре), докато в зависимост от операционната система std::wstring
е 2 байта (Windows) или 4 байта (Linux) (повече информация тук
и тук
). В крайна сметка, ако погледнете getString
ще видите, че тя приема и връща sql::SQLString
. sql::SQLString
клас е просто обвивка за std::string
.
Мисля, че трябва да посочите utf-8
като набор от символи по подразбиране за MySql :За това ще трябва да посочите следните опции за свързване
при свързване към базата данни:
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() << ").";
}
След това трябва да можете да продължите да правите запитвания към вашата база данни, както следва
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;
}
Проблемът, който сега възниква, когато искате да създадете имена на файлове с него или да го изведете в конзолата, е Windows себе си (бях тествал кода преди само с Linux и следователно не се сблъсках с този проблем преди!):По подразбиране той използва ANSI, а не UTF-8. Дори ако изведете нещо като āàčīēļš
няма да го изведе правилно, независимо дали използвате std::cout
или std::wcout
в комбинация с std::wstring
. Вместо това ще изведе ─ü├á─ì─½─ô─╝┼í
.
Ако извлечете байтовете
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;
}
ще изведе C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1
което го включва обратно в байт-към-utf8-конвертор като този
всъщност ще ви даде āàčīēļš
. Така че низът е прочетен правилно, но Windows просто не го показва правилно. Следното в комбинация с последния раздел (посочващ utf-8
като набор от символи по подразбиране в MySql) трябва да коригира всичките ви проблеми:
-
Извикване на
SetConsoleOutputCP(CP_UTF8);
отwindows.h
в началото на програмата ще коригира конзолния изход :#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; }
-
По същия начин ще трябва да адаптирате вашата рутина, която създава файловете тъй като по подразбиране също няма да бъде UTF8 (съдържанието на файловете няма да е проблем, но самото име на файла ще бъде!). Използвайте
std::ofstream
отfstream
в комбинация сstd::filesystem::u8path
отfilesystem
на библиотеката C++17 за да разрешите това:#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; }