sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo usar caracteres UTF8 en el proyecto DEFAULT c ++ O cuando usa el conector mysql para c ++ en Visual Studio 2019 (Latin7_general_ci a UTF-8)?

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); desde windows.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 de fstream en combinación con std::filesystem::u8path de la biblioteca C++17 filesystem 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;
     }