String-Vergleich ohne Berücksichtigung der Groß-/Kleinschreibung in C++ [closed]
Lesezeit: 8 Minuten
Adam
Was ist der beste Weg, um einen String-Vergleich ohne Berücksichtigung der Groß-/Kleinschreibung in C++ durchzuführen, ohne einen String in Groß- oder Kleinbuchstaben umzuwandeln?
Bitte geben Sie an, ob die Methoden Unicode-freundlich sind und wie portabel sie sind.
@[Adam](#11679): Während diese Variante in Bezug auf die Benutzerfreundlichkeit gut ist, ist sie in Bezug auf die Leistung schlecht, da sie unnötige Kopien erstellt. Ich könnte etwas übersehen, aber ich glaube, der beste (Nicht-Unicode) Weg ist die Verwendung std::stricmp. Ansonsten lies was Herb muss sagen.
– Konrad Rudolf
26. August 2008 um 12:17 Uhr
In c war man normalerweise gezwungen, die gesamte Zeichenfolge zu überschreiben und dann auf diese Weise zu vergleichen – oder würfeln Sie Ihren eigenen Vergleich: P
– Michael Dorgan
22. Mai 2010 um 1:10 Uhr
Eine spätere Frage hat eine einfachere Antwort: strcasecmp (zumindest für BSD- und POSIX-Compiler) stackoverflow.com/questions/9182912/…
– Móż
5. November 2013 um 21:39 Uhr
@Mσᶎ Diese Frage hat auch diese Antwort, mit der wichtigen Einschränkung, dass strcasecmp ist nicht Teil des Standards und fehlt bei mindestens einem gängigen Compiler.
– Markieren Sie Lösegeld
1. Dezember 2014 um 19:57 Uhr
rauben
Boost enthält dafür einen praktischen Algorithmus:
#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
}
Ist das UTF-8-freundlich? Ich denke nicht.
– vladr
30. Oktober 2010 um 0:23 Uhr
Nein, da UTF-8 aufgrund von Akzenten, Kombinationen, Bidi-Problemen usw. die Codierung identischer Zeichenfolgen mit unterschiedlichen Binärcodes zulässt.
– vy32
18. Juni 2011 um 23:35 Uhr
@vy32 Das ist absolut falsch! Die UTF-8-Kombinationen schließen sich gegenseitig aus. Es muss immer die kürzestmögliche Darstellung verwendet werden, wenn dies nicht der Fall ist, handelt es sich um eine fehlerhafte UTF-8-Sequenz oder einen Codepunkt, der mit Vorsicht behandelt werden muss.
– Wiz
10. November 2011 um 23:44 Uhr
@Wiz, Sie ignorieren das Problem der Normalisierung von Unicode-Strings. ñ kann als Kombination von ˜ gefolgt von einem n oder mit einem ñ-Zeichen dargestellt werden. Sie müssen die Unicode-String-Normalisierung verwenden, bevor Sie den Vergleich durchführen. Bitte lesen Sie den technischen Unicode-Bericht Nr. 15, unicode.org/reports/tr15
Profitieren Sie von der Norm char_traits. Denken Sie daran, dass a std::string ist in der Tat ein Typedef für std::basic_string<char>oder genauer gesagt, std::basic_string<char, std::char_traits<char> >. Die char_traits type beschreibt, wie sich Zeichen vergleichen, wie sie kopieren, wie sie gecastet werden usw. Alles, was Sie tun müssen, ist, einen neuen String darüber zu schreiben basic_stringund versehen Sie es mit Ihrem eigenen Benutzernamen char_traits die Groß- und Kleinschreibung unsensibel vergleichen.
Soweit ich aus eigenen Experimenten weiß, macht dies Ihren neuen Zeichenfolgentyp inkompatibel mit std::string.
– Zan Luchs
26. September 2012 um 21:25 Uhr
Natürlich tut es das – zu seinem eigenen Besten. Eine Zeichenfolge ohne Berücksichtigung der Groß-/Kleinschreibung ist etwas anderes: typedef std::basic_string<char, ci_char_traits<char> > istringnicht typedef std::basic_string<char, std::char_traits<char> > string.
– Andreas Spindler
9. Oktober 2012 um 9:24 Uhr
“Alles, was Sie tun müssen …”
– Tim MB
19. April 2013 um 10:03 Uhr
Jedes Sprachkonstrukt, das in diesem trivialen Fall einen solchen Wahnsinn erzwingt, sollte und kann ohne Reue aufgegeben werden.
– Erik Aronesty
14. November 2014 um 14:17 Uhr
@DaveKennedy Ich denke, Erik rät dazu, menschliche Sprachen aufzugeben diese sind die Sprachkonstrukte, die diesen Wahnsinn erzwingen. 🙂
– srm
21. März 2018 um 16:35 Uhr
Timmm
Das Problem mit Boost ist, dass Sie sich mit Boost verbinden und sich auf Boost verlassen müssen. In einigen 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 das ist, was Sie möchten.
Dies sollte genügen. Es sollte einigermaßen effizient sein. Behandelt jedoch kein 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;
}
Tatsächlich ist die Boost-String-Bibliothek eine reine Header-Bibliothek, sodass keine Verknüpfung zu irgendetwas erforderlich ist. Außerdem können Sie das Dienstprogramm „bcp“ von boost verwenden, um nur die String-Header in Ihren Quellbaum zu kopieren, sodass Sie nicht die vollständige Boost-Bibliothek benötigen.
– Gretchen
9. März 2011 um 21:47 Uhr
Gut, eine einfache Version ohne Boost-Abhängigkeit zu kennen.
– Deqing
17. Mai 2014 um 3:31 Uhr
@Anna Textbibliothek von Boost muss erstellt und verlinkt werden. Es verwendet IBM ICU.
– Behrouz.M
1. Juni 2015 um 6:46 Uhr
std::tolower sollte nicht angerufen werden char direkt, a static_cast zu unsigned char wird gebraucht.
– Evg
26. September 2020 um 9:50 Uhr
@Timmmm Ich habe mir erlaubt, dieser Antwort eine C ++ 20-Version hinzuzufügen, da ich glaube, dass hier die beste Lösung ist, und im Vergleich zu anderen Antworten in diesem Thread glaube ich, dass sie Ihren anderen Lösungen am ähnlichsten ist.
– Ben Cottrell
2. Januar um 11:39 Uhr
Derek Park
Wenn Sie sich auf einem POSIX-System befinden, können Sie verwenden strcasecmp. Diese Funktion ist jedoch nicht Teil von Standard-C und steht auch nicht unter Windows zur Verfügung. Dies führt einen Vergleich ohne Berücksichtigung der Groß-/Kleinschreibung für 8-Bit-Zeichen durch, solange das Gebietsschema POSIX ist. Wenn das Gebietsschema nicht POSIX ist, sind die Ergebnisse undefiniert (es kann also ein lokalisierter Vergleich durchgeführt werden oder nicht). Ein Breitzeichen-Äquivalent ist nicht verfügbar.
Andernfalls verfügen viele historische Implementierungen von C-Bibliotheken über die Funktionen stricmp() und strnicmp(). Visual C++ unter Windows hat all diese umbenannt, indem ihnen ein Unterstrich vorangestellt wurde, weil sie nicht Teil des ANSI-Standards sind, also heißen sie auf diesem System _stricmp oder _strnicmp. Einige Bibliotheken können auch Wide-Character- oder Multibyte-äquivalente Funktionen haben (normalerweise zB wcsicmp, mbcsicmp und so weiter genannt).
C und C++ sind beide weitgehend unwissend in Bezug auf Internationalisierungsprobleme, daher gibt es keine gute Lösung für dieses Problem, außer die Verwendung einer Bibliothek eines Drittanbieters. Kasse 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.
Münze
Sprechen Sie von einem dummen Vergleich ohne Berücksichtigung der Groß-/Kleinschreibung oder einem vollständig normalisierten Unicode-Vergleich?
Ein dummer Vergleich findet keine Zeichenfolgen, die möglicherweise gleich sind, aber nicht binär gleich sind.
Beispiel:
U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).
Sind alle gleichwertig, haben aber auch unterschiedliche binäre Darstellungen.
Das gesagt, Unicode-Normalisierung sollte eine Pflichtlektüre sein, besonders wenn Sie vorhaben, Hangul, Thaï und andere asiatische Sprachen zu unterstützen.
Außerdem hat IBM die meisten optimierten Unicode-Algorithmen so ziemlich patentiert und öffentlich zugänglich gemacht. Sie pflegen auch eine Implementierung: IBM Intensivstation
Igor Miljakow
boost::iequals ist im Fall von string nicht utf-8-kompatibel. Sie können verwenden boost::locale.
Primär — Akzente und Groß-/Kleinschreibung ignorieren, nur Grundbuchstaben vergleichen. Beispielsweise sind „Fassade“ und „Fassade“ gleich.
Sekundär – Groß-/Kleinschreibung ignorieren, aber Akzente berücksichtigen. “Fassade” und “Fassade” sind unterschiedlich, aber “Fassade” und “Fassade” sind dasselbe.
Tertiär – Groß- und Kleinschreibung beachten: „Fassade“ und „Fassade“ sind unterschiedlich. Satzzeichen ignorieren.
Quartär – berücksichtigen Sie Groß- und Kleinschreibung, Akzente und Interpunktion. Die Wörter müssen hinsichtlich der Unicode-Darstellung identisch sein.
Identisch – wie quaternär, aber auch Codepunkte vergleichen.
Mein erster Gedanke für eine Nicht-Unicode-Version war, so etwas zu tun:
@[Adam](#11679): Während diese Variante in Bezug auf die Benutzerfreundlichkeit gut ist, ist sie in Bezug auf die Leistung schlecht, da sie unnötige Kopien erstellt. Ich könnte etwas übersehen, aber ich glaube, der beste (Nicht-Unicode) Weg ist die Verwendung
std::stricmp
. Ansonsten lies was Herb muss sagen.– Konrad Rudolf
26. August 2008 um 12:17 Uhr
In c war man normalerweise gezwungen, die gesamte Zeichenfolge zu überschreiben und dann auf diese Weise zu vergleichen – oder würfeln Sie Ihren eigenen Vergleich: P
– Michael Dorgan
22. Mai 2010 um 1:10 Uhr
Eine spätere Frage hat eine einfachere Antwort: strcasecmp (zumindest für BSD- und POSIX-Compiler) stackoverflow.com/questions/9182912/…
– Móż
5. November 2013 um 21:39 Uhr
@Mσᶎ Diese Frage hat auch diese Antwort, mit der wichtigen Einschränkung, dass
strcasecmp
ist nicht Teil des Standards und fehlt bei mindestens einem gängigen Compiler.– Markieren Sie Lösegeld
1. Dezember 2014 um 19:57 Uhr