Mysql
 sql >> Database >  >> RDS >> Mysql

Come utilizzare i caratteri UTF8 nel progetto DEFAULT c++ OPPURE quando si utilizza il connettore mysql per c++ in Visual Studio 2019 (da Latin7_general_ci a UTF-8)?

Penso che il problema nel tuo caso non sia correlato a std::wstring :il std::string a 8 bit dovrebbe essere sufficiente per UTF-8 (creando un semplice std::string con i caratteri speciali "āàčīēļš" funziona bene), mentre dipende dal sistema operativo std::wstring è 2 byte (Windows) o 4 byte (Linux) (maggiori informazioni qui e qui ). Dopotutto se dai un'occhiata a getString funzione vedrai che prende e restituisce un sql::SQLString . Il sql::SQLString class è solo un semplice wrapper per un std::string .

Penso che tu debba specificare utf-8 come set di caratteri predefinito per MySql :Per questo dovrai specificare seguenti opzioni di connessione durante la connessione al database:

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

Quindi dovresti essere in grado di continuare a interrogare il tuo database come segue

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

Il problema che ora emerge quando vuoi creare nomi di file con esso o inviarlo alla console è Windows stesso (avevo testato il codice in precedenza solo con Linux e quindi non ho riscontrato questo problema prima!):Per impostazione predefinita utilizza ANSI e non UTF-8. Anche se emetti qualcosa come āàčīēļš non lo produrrà correttamente, non importa se stai usando un std::cout o std::wcout in combinazione con std::wstring . Invece produrrà ─ü├á─ì─½─ô─╝┼í .

Se estrai i 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;
}

emetterà C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1 che ricollegandolo a un convertitore da byte a utf8 come questo ti darà infatti āàčīēļš . Quindi la stringa è stata letta correttamente ma Windows non la visualizza correttamente. Quanto segue in combinazione con l'ultima sezione (specificando utf-8 come set di caratteri predefinito in MySql) dovrebbe risolvere tutti i tuoi problemi:

  • Una chiamata a SetConsoleOutputCP(CP_UTF8); da windows.h all'inizio del programma correggerà l'output della 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;
     }
    
  • Allo stesso modo dovrai adattare la tua routine che crea i file poiché per impostazione predefinita non sarà anche UTF8 (il contenuto dei file non sarà un problema ma lo sarà il nome del file stesso!). Usa std::ofstream da fstream in combinazione con std::filesystem::u8path dalla libreria C++17 filesystem per risolvere questo problema:

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