Creo que el problema en tu caso no está relacionado con std::wstring
:el std::string
de 8 bits debería ser suficiente para UTF-8 (creando un simple std::string
con los caracteres especiales "āàčīēļš"
simplemente funciona bien), dependiendo del sistema operativo std::wstring
es de 2 Byte (Windows) o de 4 Byte (Linux) (más información aquí
y aquí
). Después de todo, si echas un vistazo a getString
verá que toma y devuelve un sql::SQLString
. El sql::SQLString
la clase es solo un contenedor simple para un std::string
.
Creo que tienes que especificar utf-8
como conjunto de caracteres predeterminado para MySql :Para esto tendrás que especificar el siguientes opciones de conexión
al conectarse a la base de datos:
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() << ").";
}
Entonces debería poder continuar consultando su base de datos de la siguiente manera
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;
}
El problema que surge ahora cuando desea crear nombres de archivo con él o enviarlo a la consola es Windows (¡Había probado el código antes solo con Linux y, por lo tanto, no me encontré con este problema antes!):Por defecto, usa ANSI y no UTF-8. Incluso si generas algo como āàčīēļš
no lo generará correctamente sin importar si está utilizando un std::cout
o std::wcout
en combinación con std::wstring
. En su lugar, generará ─ü├á─ì─½─ô─╝┼í
.
Si extrae los bytes
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;
}
generará C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1
que lo vuelve a conectar a un convertidor de bytes a utf8 como este
de hecho te dará āàčīēļš
. Entonces, la cadena se leyó correctamente, pero Windows simplemente no la muestra correctamente. Lo siguiente en combinación con la última sección (especificando utf-8
como conjunto de caracteres predeterminado en MySql) debería solucionar todos sus problemas:
-
Una llamada a
SetConsoleOutputCP(CP_UTF8);
desdewindows.h
al inicio del programa arreglará la salida de la consola :#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; }
-
De igual forma tendrás que adaptar tu rutina que crea los archivos ya que, de forma predeterminada, tampoco será UTF8 (¡el contenido de los archivos no será un problema, pero el nombre del archivo sí lo será!). Utilice
std::ofstream
defstream
en combinación constd::filesystem::u8path
de la biblioteca C++17filesystem
para resolver esto:#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; }