Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie verwende ich UTF8-Zeichen im DEFAULT-C++-Projekt ODER bei Verwendung des MySQL-Connectors für C++ in Visual Studio 2019 (Latin7_general_ci bis UTF-8)?

Ich denke, das Problem in Ihrem Fall hängt nicht mit std::wstring zusammen :der 8-Bit std::string sollte für UTF-8 ausreichen (Erstellen eines einfachen std::string mit den Sonderzeichen "āàčīēļš" funktioniert einfach gut), während je nach Betriebssystem std::wstring ist 2 Byte (Windows) oder 4 Byte (Linux) (weitere Informationen hier ). und hier ). Immerhin, wenn Sie sich den getString ansehen Funktion sehen Sie, dass sie einen sql::SQLString nimmt und zurückgibt . Der sql::SQLString class ist nur ein einfacher Wrapper für einen std::string .

Ich denke, Sie müssen utf-8 angeben als Standardzeichensatz für MySql :Dazu müssen Sie folgende Verbindungsoptionen beim Verbinden mit der Datenbank:

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

Dann sollten Sie Ihre Datenbank wie folgt weiter abfragen können

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

Das Problem, das nun auftaucht, wenn man damit Dateinamen erstellen oder auf die Konsole ausgeben will, ist Windows selbst (Ich hatte den Code zuvor nur mit Linux getestet und bin daher vorher nicht auf dieses Problem gestoßen!):Standardmäßig verwendet es ANSI und nicht UTF-8. Auch wenn Sie so etwas wie āàčīēļš ausgeben es wird es nicht korrekt ausgeben, egal ob Sie einen std::cout verwenden oder std::wcout in Kombination mit std::wstring . Stattdessen wird ─ü├á─ì─½─ô─╝┼í ausgegeben .

Wenn Sie die Bytes extrahieren

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

es wird C4 81 C3 A0 C4 8D C4 AB C4 93 C4 BC C5 A1 ausgegeben die es wieder in einen Byte-zu-utf8-Konverter wie diesen einstecken wird Ihnen tatsächlich āàčīēļš geben . Die Zeichenfolge wurde also korrekt gelesen, aber Windows zeigt sie einfach nicht korrekt an. Das Folgende in Kombination mit dem letzten Abschnitt (Angabe von utf-8 als Standardzeichensatz in MySql) sollte alle Ihre Probleme beheben:

  • Ein Aufruf von SetConsoleOutputCP(CP_UTF8); aus windows.h beim Start des Programms korrigiert die Konsolenausgabe :

     #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;
     }
    
  • Ebenso müssen Sie Ihre Routine anpassen, die die Dateien erstellt da es standardmäßig auch nicht UTF8 sein wird (Der Inhalt der Dateien wird kein Problem sein, aber der Dateiname selbst wird es sein!). Verwenden Sie std::ofstream von fstream in Kombination mit std::filesystem::u8path aus der C++17-Bibliothek filesystem um dies zu beheben:

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