Was ist der beste Weg, um case-insensitive String-Vergleich in C++ ohne Umwandlung einer Zeichenfolge in alle Groß- oder Kleinschreibung zu tun?
Bitte geben Sie an, ob die Methoden Unicode-freundlich sind und wie portabel sie sind.
Was ist der beste Weg, um case-insensitive String-Vergleich in C++ ohne Umwandlung einer Zeichenfolge in alle Groß- oder Kleinschreibung zu tun?
Bitte geben Sie an, ob die Methoden Unicode-freundlich sind und wie portabel sie sind.
Boost enthält einen praktischen Algorithmus für diese Aufgabe:
#include <boost/algorithm/string.hpp>
// Or, for fewer header dependencies:
//#include <boost/algorithm/string/predicate.hpp>
std::string str1 = "hello, world!";
std::string str2 = "HELLO, WORLD!";
if (boost::iequals(str1, str2))
{
// Strings are identical
}
Das Problem mit Boost ist, dass man sich mit Boost verbinden und von ihm abhängig machen muss. In manchen Fällen nicht einfach (z. B. Android).
Und die Verwendung von char_traits bedeutet alle Bei Ihren Vergleichen wird die Groß- und Kleinschreibung nicht beachtet, was normalerweise nicht erwünscht ist.
Das sollte genügen. Es sollte einigermaßen effizient sein. Verarbeitet allerdings keinen Unicode oder ähnliches.
bool iequals(const string& a, const string& b)
{
unsigned int sz = a.size();
if (b.size() != sz)
return false;
for (unsigned int i = 0; i < sz; ++i)
if (tolower(a[i]) != tolower(b[i]))
return false;
return true;
}
Update: Bonus C++14-Version ( #include <algorithm>
):
bool iequals(const string& a, const string& b)
{
return std::equal(a.begin(), a.end(),
b.begin(), b.end(),
[](char a, char b) {
return tolower(a) == tolower(b);
});
}
Update: C++20-Version mit std::ranges
:
#include <ranges>
#include <algorithm>
#include <string>
bool iequals(const std::string_view& lhs, const std::string_view& rhs) {
auto to_lower{ std::ranges::views::transform(std::tolower) };
return std::ranges::equal(lhs | to_lower, rhs | to_lower);
}
Nutzen Sie die Vorteile der Standard char_traits
. Es sei daran erinnert, dass eine std::string
ist in Wirklichkeit ein Typendefinition für std::basic_string<char>
oder noch deutlicher, std::basic_string<char, std::char_traits<char> >
. Die char_traits
type beschreibt, wie Zeichen verglichen werden, wie sie kopieren, wie sie werfen usw. Alles, was Sie tun müssen, ist eine neue Zeichenkette zu typisieren basic_string
und versehen Sie es mit Ihren eigenen benutzerdefinierten char_traits
den Fall unsensibel zu vergleichen.
struct ci_char_traits : public char_traits<char> {
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
static int compare(const char* s1, const char* s2, size_t n) {
while( n-- != 0 ) {
if( toupper(*s1) < toupper(*s2) ) return -1;
if( toupper(*s1) > toupper(*s2) ) return 1;
++s1; ++s2;
}
return 0;
}
static const char* find(const char* s, int n, char a) {
while( n-- > 0 && toupper(*s) != toupper(a) ) {
++s;
}
return s;
}
};
typedef std::basic_string<char, ci_char_traits> ci_string;
Die Einzelheiten finden Sie unter Guru der Woche Nummer 29 .
Wenn Sie auf einem POSIX-System arbeiten, können Sie strcasecmp . Diese Funktion ist jedoch nicht Teil von Standard-C und auch nicht unter Windows verfügbar. Sie führt einen Groß-/Kleinschreibung-unabhängigen Vergleich für 8-Bit-Zeichen durch, sofern die Locale POSIX ist. Wenn das Gebietsschema nicht POSIX ist, sind die Ergebnisse undefiniert (es kann also ein lokalisierter Vergleich durchgeführt werden, oder auch nicht). Eine Entsprechung für breite Zeichen ist nicht verfügbar.
Andernfalls verfügt eine große Anzahl historischer C-Bibliotheksimplementierungen über die Funktionen stricmp() und strnicmp(). Visual C++ unter Windows hat alle diese Funktionen umbenannt, indem es ihnen einen Unterstrich vorangestellt hat, weil sie nicht Teil des ANSI-Standards sind, so dass sie auf diesem System _stricmp oder _strnicmp . Einige Bibliotheken verfügen möglicherweise auch über Funktionen, die Wide-Character- oder Multibyte-Äquivalente darstellen (typischerweise z. B. wcsicmp, mbcsicmp usw.).
C und C++ sind beide weitgehend ignorant gegenüber Internationalisierungsproblemen, so dass es keine gute Lösung für dieses Problem gibt, außer eine Bibliothek eines Drittanbieters zu verwenden. Schauen Sie sich IBM ICU (Internationale Komponenten für Unicode) wenn Sie eine robuste Bibliothek für C/C++ benötigen. ICU ist sowohl für Windows- als auch für Unix-Systeme geeignet.
Sprechen Sie von einem dummen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung oder einem vollständigen normalisierten Unicode-Vergleich?
Ein dummer Vergleich findet keine Zeichenketten, die gleich sein könnten, aber nicht binär gleich sind.
Exemple :
U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).
sind alle gleichwertig, aber sie haben auch unterschiedliche binäre Darstellungen.
Davon abgesehen, Unicode-Normalisierung sollte eine Pflichtlektüre sein, insbesondere wenn Sie Hangul, Thaï und andere asiatische Sprachen unterstützen wollen.
Außerdem hat IBM die meisten optimierten Unicode-Algorithmen patentiert und öffentlich zugänglich gemacht. Sie unterhalten auch eine Implementierung : IBM INTENSIVSTATION
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.