Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como usar caracteres UTF8 no projeto DEFAULT c++ OU ao usar o conector mysql para c++ no visual studio 2019 (Latin7_general_ci para UTF-8)?


Acho que o problema no seu caso não está relacionado a std::wstring :o std::string de 8 bits deve ser suficiente para UTF-8 (criando um simples std::string com os caracteres especiais "āàčīēļš" funciona bem), dependendo do sistema operacional std::wstring é de 2 Byte (Windows) ou 4 Byte (Linux) (mais informações aqui e aqui ). Afinal, se você der uma olhada no getString você verá que ela recebe e retorna um sql::SQLString . O sql::SQLString class é apenas um wrapper simples para um std::string .

Acho que você precisa especificar utf-8 como conjunto de caracteres padrão para MySql :Para isso, você terá que especificar o seguindo opções de conexão ao conectar-se ao banco de dados:
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() << ").";
}

Então você poderá continuar a consultar seu banco de dados da seguinte maneira
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;
}

O problema que surge agora quando você deseja criar nomes de arquivos com ele ou enviá-lo para o console é Windows em si (eu havia testado o código antes apenas com Linux e, portanto, não me deparei com esse problema antes!):Por padrão, ele usa ANSI e não UTF-8. Mesmo se você produzir algo como āàčīēļš ele não o produzirá corretamente, não importa se você estiver usando um std::cout ou std::wcout em combinação com std::wstring . Em vez disso, ele produzirá ─ü├á─ì─½─ô─╝┼í .

Se você extrair os 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;
}

ele produzirá C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1 que o conecta novamente a um conversor byte-to-utf8, como este de fato lhe dará āàčīēļš . Portanto, a string foi lida corretamente, mas o Windows não está exibindo-a corretamente. O seguinte em combinação com a última seção (especificando utf-8 como conjunto de caracteres padrão no MySql) deve corrigir todos os seus problemas:

  • Uma chamada para SetConsoleOutputCP(CP_UTF8); de windows.h no início do programa corrigirá a saída do 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;
     }
    

  • Da mesma forma você terá que adaptar sua rotina que cria os arquivos como padrão, também não será UTF8 (o conteúdo dos arquivos não será um problema, mas o próprio nome do arquivo será!). Use std::ofstream de fstream em combinação com std::filesystem::u8path da biblioteca C++17 filesystem para resolver isso:
     #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;
     }