tl; dr
Verwenden Sie die ICU-Bibliothek . Wenn Sie dies nicht tun, wird Ihre Konvertierungsroutine in Fällen, in denen Sie wahrscheinlich gar nicht wissen, dass sie existieren, stillschweigend unterbrochen.
Zuerst müssen Sie eine Frage beantworten: Wie lautet die Kodierung Ihrer std::string
? Ist es ISO-8859-1? Oder vielleicht ISO-8859-8? Oder Windows Codepage 1252? Weiß das, was auch immer Sie zum Konvertieren von Groß- und Kleinbuchstaben verwenden? (Oder scheitert es kläglich für Charaktere vorbei 0x7f
?)
Wenn Sie UTF-8 (die einzig vernünftige Wahl unter den 8-Bit-Codierungen) mit std::string
als Container verwenden, täuschen Sie sich bereits in der Annahme, dass Sie immer noch die Kontrolle über die Dinge haben, da Sie eine Multibyte-Zeichenfolge in einem Container speichern das ist sich des Multibyte-Konzepts nicht bewusst. Sogar etwas so Einfaches wie .substr()
eine tickende Zeitbombe. (Da das Aufteilen einer Multibyte-Sequenz zu einer ungültigen (Unter-) Zeichenfolge führt.)
Und sobald Sie etwas versuchen std::toupper( 'ß' )
, in irgendeiner Codierung, sind Sie in großen Schwierigkeiten. (Weil es mit der Standardbibliothek, die nur ein Ergebniszeichen liefern kann , das "SS"
hier nicht benötigt wird , einfach nicht "richtig" ist.) [1] Ein anderes Beispiel wäre std::tolower( 'I' )
, das je nach Gebietsschema unterschiedliche Ergebnisse liefern sollte . In Deutschland 'i'
wäre das richtig; In der Türkei ist 'ı'
(LATIN SMALL LETTER DOTLESS I) das erwartete Ergebnis (das wiederum mehr als ein Byte in der UTF-8-Codierung beträgt). Ein weiteres Beispiel ist das griechische Sigma , Groß- '∑'
und Kleinschreibung 'σ'
... außer am Ende eines Wortes, wo es sich befindet 'ς'
.
Also, jeder Fall Konvertierung , die auf einem Zeichen in einer Zeit arbeitet, oder noch schlimmer, ein Byte zu einem Zeitpunkt, wird durch Design gebrochen.
Dann gibt es den Punkt , dass die Standard - Bibliothek, für das, was es ist dazu in der Lage ist abhängig davon , welche Lokalisationen werden unterstützt auf der Maschine Ihre Software auf läuft ... und was tun Sie , wenn es nicht ist?
Also , was Sie wirklich suchen, ist ein String - Klasse , die mit all dies zu tun richtig fähig ist, und das ist nicht eine der std::basic_string<>
Varianten .
(C ++ 11 Hinweis: std::u16string
und std::u32string
sind besser , aber immer noch nicht perfekt. C ++ 20 gebracht std::u8string
, aber alles, was Sie tun, ist die Codierung anzugeben. In vielerlei Hinsicht bleiben sie immer noch unwissend über Unicode-Mechanik, wie Normalisierung, Kollatierung, .. .)
Während Boost in Bezug auf die API gut aussieht , ist Boost.Locale im Grunde ein Wrapper um die Intensivstation . Wenn Boost mit ICU-Unterstützung kompiliert wird, ist Boost.Locale auf die für die Standardbibliothek kompilierte Gebietsschema-Unterstützung beschränkt.
Und glauben Sie mich, immer Boost zu kompilieren mit ICU manchmal einen echten Schmerzen sein kann. (Es gibt keine vorkompilierten Binärdateien für Windows, daher müssten Sie sie zusammen mit Ihrer Anwendung bereitstellen, und das öffnet eine ganz neue Dose Würmer ...)
Daher würde ich persönlich empfehlen, die volle Unicode-Unterstützung direkt aus dem Maul des Pferdes zu erhalten und die Intensivbibliothek direkt zu nutzen:
#include <unicode/unistr.h>
#include <unicode/ustream.h>
#include <unicode/locid.h>
#include <iostream>
int main()
{
/* "Odysseus" */
char const * someString = u8"ΟΔΥΣΣΕΥΣ";
icu::UnicodeString someUString( someString, "UTF-8" );
// Setting the locale explicitly here for completeness.
// Usually you would use the user-specified system locale,
// which *does* make a difference (see ı vs. i above).
std::cout << someUString.toLower( "el_GR" ) << "\n";
std::cout << someUString.toUpper( "el_GR" ) << "\n";
return 0;
}
Kompilieren (in diesem Beispiel mit G ++):
g++ -Wall example.cpp -licuuc -licuio
Das gibt:
ὀδυσσεύς
Beachten Sie, dass die Σ <-> σ-Konvertierung in der Mitte des Wortes und die Σ <-> ς-Konvertierung am Ende des Wortes. Keine <algorithm>
basierende Lösung kann Ihnen das geben.
[1] 2017 entschied der Rat für deutsche Rechtschreibung, dass "" "U + 1E9E LATIN CAPITAL LETTER SHARP S offiziell als Option neben der traditionellen" SS "-Konvertierung verwendet werden kann, um Unklarheiten zu vermeiden, z. B. in Pässen (bei denen Namen groß geschrieben werden) ). Mein schönes Beispiel, das durch die Entscheidung des Komitees überholt wurde ...