Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment utiliser les caractères UTF8 dans le projet DEFAULT c++ OU lors de l'utilisation du connecteur mysql pour c++ dans Visual Studio 2019 (Latin7_general_ci vers UTF-8) ?

Je pense que le problème dans votre cas n'est pas lié à std::wstring :le std::string 8 bits devrait être suffisant pour UTF-8 (créer un simple std::string avec les caractères spéciaux "āàčīēļš" fonctionne très bien), tout en dépendant du système d'exploitation std::wstring est de 2 octets (Windows) ou de 4 octets (Linux) (plus d'informations ici et ici ). Après tout, si vous regardez le getString vous verrez qu'elle prend et renvoie un sql::SQLString . Le sql::SQLString la classe est juste un simple wrapper pour un std::string .

Je pense que vous devez spécifier utf-8 comme jeu de caractères par défaut pour MySql :Pour cela vous devrez spécifier le options de connexion suivantes lors de la connexion à la base de données :

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() << ").";
}

Ensuite, vous devriez pouvoir continuer à interroger votre base de données comme suit

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;
}

Le problème qui apparaît maintenant lorsque vous souhaitez créer des noms de fichiers avec ou les sortir sur la console est Windows lui-même (j'avais testé le code auparavant avec Linux uniquement et je n'avais donc pas rencontré ce problème auparavant !) :par défaut, il utilise ANSI et non UTF-8. Même si vous affichez quelque chose comme āàčīēļš il ne le sortira pas correctement, peu importe si vous utilisez un std::cout ou std::wcout en combinaison avec std::wstring . Au lieu de cela, il affichera ─ü├á─ì─½─ô─╝┼í .

Si vous extrayez les octets

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;
}

il affichera C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1 qui le rebranche dans un convertisseur octet en utf8 tel que celui-ci vous donnera en fait āàčīēļš . La chaîne a donc été lue correctement, mais Windows ne l'affiche tout simplement pas correctement. Ce qui suit en combinaison avec la dernière section (en spécifiant utf-8 comme jeu de caractères par défaut dans MySql) devrait résoudre tous vos problèmes :

  • Un appel à SetConsoleOutputCP(CP_UTF8); depuis windows.h au début du programme corrigera la sortie de la console :

     #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 même vous devrez adapter votre routine qui crée les fichiers car par défaut, ce ne sera pas non plus UTF8 (le contenu des fichiers ne sera pas un problème mais le nom de fichier lui-même le sera !). Utilisez std::ofstream depuis fstream en combinaison avec std::filesystem::u8path de la bibliothèque C++17 filesystem pour résoudre ce problème :

     #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;
     }