String-Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung in C ++ [geschlossen]
373
Was ist der beste Weg, um einen String-Vergleich ohne Berücksichtigung der Groß- und 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): Obwohl diese Variante in Bezug auf die Benutzerfreundlichkeit gut ist, ist sie in Bezug auf die Leistung schlecht, da unnötige Kopien erstellt werden. Ich könnte etwas übersehen, aber ich glaube, der beste Weg (ohne Unicode) ist die Verwendung std::stricmp. Ansonsten lesen Sie, was Herb zu sagen hat .
Konrad Rudolph
In c war man normalerweise gezwungen, die gesamte Saite zu übersteigen und dann auf diese Weise zu vergleichen - oder einen eigenen Vergleich zu erstellen: P
@ Mσᶎ Diese Frage hat auch diese Antwort, mit der wichtigen Einschränkung, strcasecmpdie nicht Teil des Standards ist und in mindestens einem gemeinsamen Compiler fehlt.
Mark Ransom
Antworten:
317
Boost enthält hierfü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}
Nein, da UTF-8 die Codierung identischer Zeichenfolgen mit unterschiedlichen Binärcodes aufgrund von Akzenten, Kombinationen, Bidi-Problemen usw. ermöglicht
vy32
10
@ vy32 Das ist absolut falsch! Die UTF-8-Kombinationen schließen sich gegenseitig aus. Es muss immer die kürzestmögliche Darstellung verwendet werden. Ist dies nicht der Fall, handelt es sich um eine fehlerhafte UTF-8-Sequenz oder einen fehlerhaften Codepunkt, der mit Vorsicht behandelt werden muss.
Wiz
48
@Wiz, Sie ignorieren das Problem der Normalisierung von Unicode-Zeichenfolgen. ñ kann als Kombination ˜ gefolgt von einem n oder mit einem ñ-Zeichen dargestellt werden. Sie müssen die Unicode-String-Normalisierung verwenden, bevor Sie den Vergleich durchführen können. Bitte überprüfen Sie Unicode Technical Report # 15, unicode.org/reports/tr15
Nutzen Sie den Standard char_traits. Denken Sie daran, dass a std::stringtatsächlich ein typedef für std::basic_string<char>oder expliziter ist std::basic_string<char, std::char_traits<char> >. Der char_traitsTyp beschreibt, wie Zeichen verglichen werden, wie sie kopiert werden, wie sie umgewandelt werden usw. Alles, was Sie tun müssen, ist, eine neue Zeichenfolge zu überschreiben basic_stringund sie mit Ihrer eigenen benutzerdefinierten Zeichenfolge zu versehen, bei der char_traitsGroß- und Kleinschreibung nicht berücksichtigt wird.
Soweit ich aus meinen eigenen Experimenten weiß, ist Ihr neuer String-Typ dadurch nicht mit std :: string kompatibel.
Zan Lynx
8
Natürlich tut es das - zu seinem eigenen Besten. Eine Zeichenfolge, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird, 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
232
"Alles was Sie tun müssen ..."
Tim MB
3
@ Nathan wahrscheinlich einen Compiler verwenden, der in der Lage ist, grundlegende CSE für den Code auszuführen ...
The Paramagnetic Croissant
17
Jedes Sprachkonstrukt, das in diesem trivialen Fall einen solchen Wahnsinn erzwingt, sollte und kann ohne Reue aufgegeben werden.
Erik Aronesty
86
Das Problem mit Boost ist, dass Sie sich mit Boost verbinden und von Boost abhängen müssen. In einigen Fällen nicht einfach (zB Android).
Die Verwendung von char_traits bedeutet, dass bei all Ihren Vergleichen die Groß- und Kleinschreibung nicht berücksichtigt wird. Dies ist normalerweise nicht das, was Sie möchten.
Das sollte ausreichen. Es sollte einigermaßen effizient sein. Behandelt jedoch keinen Unicode oder ähnliches.
bool iequals(const string& a,const string& b){unsignedint sz = a.size();if(b.size()!= sz)returnfalse;for(unsignedint i =0; i < sz;++i)if(tolower(a[i])!= tolower(b[i]))returnfalse;returntrue;}
Update: Bonus C ++ 14 Version ( #include <algorithm>):
Tatsächlich ist die Boost-String-Bibliothek eine reine Header-Bibliothek, sodass keine Verknüpfung zu irgendetwas erforderlich ist. Sie können auch das Dienstprogramm 'bcp' von boost verwenden, um nur die Zeichenfolgenheader in Ihren Quellbaum zu kopieren, sodass Sie nicht die vollständige Boost-Bibliothek benötigen.
Gretchen
Ah, ich wusste nichts über bcp, es sieht wirklich nützlich aus. Danke für die Information!
Timmmm
9
Gut zu wissen, eine einfache und nicht Boost-abhängige Version.
Deqing
2
@Anna Textbibliothek von Boost muss erstellt und verknüpft werden. Es verwendet IBM ICU.
Behrouz.M
Auch verfügbar mit C ++ 11
Mars
58
Wenn Sie sich auf einem POSIX-System befinden, können Sie strcasecmp verwenden . Diese Funktion ist jedoch weder Teil von Standard C noch unter Windows verfügbar. Dadurch wird ein Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung für 8-Bit-Zeichen durchgeführt, sofern das Gebietsschema POSIX ist. Wenn das Gebietsschema nicht POSIX ist, sind die Ergebnisse undefiniert (daher wird möglicherweise ein lokalisierter Vergleich durchgeführt oder nicht). Ein Breitzeichenäquivalent ist nicht verfügbar.
Andernfalls haben viele historische C-Bibliotheksimplementierungen die Funktionen stricmp () und strnicmp (). Visual C ++ unter Windows hat all dies umbenannt, indem ihnen ein Unterstrich vorangestellt wurde, da sie nicht Teil des ANSI-Standards sind. Auf diesem System heißen sie also _stricmp oder _strnicmp . Einige Bibliotheken verfügen möglicherweise auch über Breitzeichen- oder Multibyte-äquivalente Funktionen (normalerweise z. B. wcsicmp, mbcsicmp usw.).
C und C ++ kennen beide Internationalisierungsprobleme weitgehend nicht, daher gibt es keine gute Lösung für dieses Problem, außer die Verwendung einer Bibliothek eines Drittanbieters. Schauen Sie sich IBM ICU (International Components for Unicode) an, wenn Sie eine robuste Bibliothek für C / C ++ benötigen. Die Intensivstation ist sowohl für Windows- als auch für Unix-Systeme geeignet.
Sprechen Sie über einen dummen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung oder einen vollständig normalisierten Unicode-Vergleich?
Bei einem dummen Vergleich werden keine Zeichenfolgen gefunden, die möglicherweise gleich, 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.
Die Unicode-Normalisierung sollte jedoch obligatorisch sein, insbesondere wenn Sie Hangul, Thaï und andere asiatische Sprachen unterstützen möchten.
Außerdem hat IBM die am meisten optimierten Unicode-Algorithmen patentiert und öffentlich zugänglich gemacht. Sie pflegen auch eine Implementierung: IBM ICU
Primär - Akzente und Groß- / Kleinschreibung ignorieren und nur Basisbuchstaben vergleichen. Zum Beispiel sind "Fassade" und "Fassade" gleich.
Sekundär - Groß- und Kleinschreibung ignorieren, aber Akzente berücksichtigen. "Fassade" und "Fassade" sind unterschiedlich, aber "Fassade" und "Fassade" sind gleich.
Tertiär - berücksichtigen Sie sowohl Fall als auch Akzente: "Fassade" und "Fassade" sind unterschiedlich. Interpunktion ignorieren.
Quartär - Berücksichtigen Sie alle Groß- und Kleinschreibung, Akzente und Interpunktion. Die Wörter müssen hinsichtlich der Unicode-Darstellung identisch sein.
Identisch - wie quaternär, aber vergleichen Sie auch Codepunkte.
Sie können strcasecmpunter Unix oder stricmpWindows verwenden.
Eine Sache, die bisher nicht erwähnt wurde, ist, dass es nützlich ist, zuerst die Länge der beiden Zeichenfolgen zu vergleichen, wenn Sie stl-Zeichenfolgen mit diesen Methoden verwenden, da diese Informationen Ihnen bereits in der Zeichenfolgenklasse zur Verfügung stehen. Dies könnte verhindern, dass der kostspielige Zeichenfolgenvergleich durchgeführt wird, wenn die beiden Zeichenfolgen, die Sie vergleichen, überhaupt nicht gleich lang sind.
Da das Bestimmen der Länge einer Zeichenfolge darin besteht, jedes Zeichen in der Zeichenfolge zu durchlaufen und mit 0 zu vergleichen, gibt es wirklich einen so großen Unterschied zwischen dem und dem sofortigen Vergleichen der Zeichenfolgen? Ich denke, Sie erhalten eine bessere Speicherlokalität, wenn beide Zeichenfolgen nicht übereinstimmen, aber im Falle einer Übereinstimmung wahrscheinlich fast die doppelte Laufzeit.
Das ist eine lustige kleine Tatsache, hat aber hier wenig Einfluss. strcasecmp () und stricmp () verwenden beide nicht dekorierte C-Strings, sodass kein std :: string beteiligt ist.
uliwitness
3
Diese Methoden geben -1 zurück, wenn Sie "a" mit "ab" vergleichen. Die Längen sind unterschiedlich, aber "a" steht vor "ab". Ein einfacher Vergleich der Längen ist also nicht möglich, wenn der Anrufer sich um die Bestellung kümmert.
Ironischerweise sind die "Wide Character Codes" von Microsoft NICHT Unicode-sauber, da sie keine Unicode-Normalisierung verarbeiten.
vy32
13
Ich versuche, eine gute Antwort aus allen Beiträgen zusammenzustellen, also hilf mir, diese zu bearbeiten:
Hier ist eine Methode, um dies zu tun, obwohl sie die Zeichenfolgen transformiert und nicht Unicode-freundlich ist, sollte sie portabel sein, was ein Plus ist:
Nach dem, was ich gelesen habe, ist dies portabler als stricmp (), da stricmp () nicht Teil der Standardbibliothek ist, sondern nur von den meisten Compiler-Anbietern implementiert wird.
Um eine wirklich Unicode-freundliche Implementierung zu erhalten, müssen Sie anscheinend die Standardbibliothek verlassen. Eine gute Bibliothek von Drittanbietern ist die IBM ICU (International Components for Unicode).
Auch boost :: iequals bietet ein ziemlich gutes Dienstprogramm für diese Art von Vergleich.
Kannst du bitte sagen, was bedeutet :: tolower, warum du tolower anstelle von tolower () verwenden kannst und was ist '::' vorher? danke
VextoR
17
Dies ist keine sehr effiziente Lösung - Sie erstellen Kopien beider Zeichenfolgen und transformieren sie alle, auch wenn das erste Zeichen unterschiedlich ist.
Timmmm
2
Wenn Sie trotzdem eine Kopie erstellen möchten, warum nicht als Wert anstatt als Referenz übergeben?
Celticminstrel
Ich denke, es ist ein einfacher Tipp ohne Boost. :)
cmcromance
1
Die Frage fragt ausdrücklich, nicht transformdie gesamte Zeichenfolge vor dem Vergleich
Sie können den obigen Code in C ++ 14 verwenden, wenn Sie nicht in der Lage sind, Boost zu verwenden. Sie müssen std::towlowerfür breite Zeichen verwenden.
Ich denke, Sie müssen str1.size() == str2.size() &&der Vorderseite ein hinzufügen , damit die Grenzen nicht überschritten werden, wenn str2 ein Präfix von str1 ist.
ɲeuroburɳ
11
Der Boost.String Bibliothek verfügt über zahlreiche Algorithmen für Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung usw.
Sie könnten Ihre eigenen implementieren, aber warum sollten Sie sich die Mühe machen, wenn dies bereits geschehen ist?
Es gibt keinen Weg, der mit std :: string integriert ist?
WilliamKF
6
Nein, gibt es nicht.
Dean Harding
3
"... warum sich die Mühe machen, wenn es schon fertig ist?" - Was ist, wenn Sie Boost nicht verwenden? Das OP hatte das Tag mit der Frage nicht.
JWW
11
Zu Ihrer Information, strcmp()und stricmp()sind anfällig für Pufferüberlauf, da sie nur verarbeitet werden, bis sie einen Null-Terminator erreichen. Es ist sicherer zu bedienen _strncmp()und _strnicmp().
Richtig, obwohl das Überlesen eines Puffers wesentlich weniger gefährlich ist als das Überschreiben eines Puffers.
Adam Rosenfield
4
stricmp()und strnicmp()sind nicht Teil des POSIX-Standards :-( Wie auch immer Sie finden strcasecmp()können strcasecmp_l(), strncasecmp()und strncasecmp_l()im POSIX-Header strings.h:-) siehe opengroup.org
olibre
2
@AdamRosenfield 'schlimmer' hängt vom Kontext ab. In der Sicherheit besteht der springende Punkt beim Überschreiben manchmal darin, überlesen zu werden.
Diese Methode ist möglicherweise unsicher und nicht portabel. std::tolowerfunktioniert nur, wenn das Zeichen ASCII-codiert ist. Es gibt keine solche Garantie für std::string- so kann es leicht undefiniertes Verhalten sein.
Plasmacel
@plasmacel Verwenden Sie dann eine Funktion, die mit anderen Codierungen funktioniert.
Brian Rodriguez
9
Für meine grundlegenden Anforderungen zum Vergleichen von Zeichenfolgen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird, möchte ich keine externe Bibliothek verwenden, und ich möchte auch keine separate Zeichenfolgenklasse mit Merkmalen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird und die nicht mit allen anderen Zeichenfolgen kompatibel ist.
Eine einfache Funktion mit einer Überladung für char und einer anderen für whar_t. Verwendet nichts, was nicht dem Standard entspricht, sollte also auf jeder Plattform in Ordnung sein.
Der Gleichheitsvergleich berücksichtigt keine Probleme wie Codierung mit variabler Länge und Unicode-Normalisierung, aber basic_string unterstützt das sowieso nicht und ist normalerweise kein Problem.
In Fällen, in denen eine ausgefeiltere lexikografische Manipulation von Text erforderlich ist, müssen Sie einfach eine Drittanbieter-Bibliothek wie Boost verwenden, was zu erwarten ist.
Sie könnten diese eine Funktion wahrscheinlich machen, wenn Sie sie zu einer Vorlage machen und basic_string <T> anstelle separater String- / Wstring-Versionen verwenden würden?
uliwitness
2
Wie würde die einzelne Funktionsvorlage entweder toupper oder towupper aufrufen, ohne auf Spezialisierung oder Makros zurückzugreifen? Eine Funktionsüberladung scheint eine einfachere und angemessenere Implementierung zu sein als beide.
Neutrino
9
Kurz und nett. Keine anderen Abhängigkeiten als erweiterte std C lib.
strcasecmp(str1.c_str(), str2.c_str())==0
gibt true zurück , wenn str1und str2gleich sind.
strcasecmpkann nicht existieren, es könnte Analoga geben stricmp,strcmpi usw.
Beispielcode:
#include<iostream>#include<string>#include<string.h>//For strcasecmp(). Also could be found in <mem.h>usingnamespace std;/// Simple wrapperinlinebool str_ignoreCase_cmp(std::string const& s1, std::string const& s2){if(s1.length()!= s2.length())returnfalse;// optimization since std::string holds length in variable.return strcasecmp(s1.c_str(), s2.c_str())==0;}/// Function object - comparatorstructStringCaseInsensetiveCompare{booloperator()(std::string const& s1, std::string const& s2){if(s1.length()!= s2.length())returnfalse;// optimization since std::string holds length in variable.return strcasecmp(s1.c_str(), s2.c_str())==0;}booloperator()(constchar*s1,constchar* s2){return strcasecmp(s1,s2)==0;}};/// Convert bool to stringinlinecharconst* bool2str(bool b){return b?"true":"false";}int main(){
cout<< bool2str(strcasecmp("asd","AsD")==0)<<endl;
cout<< bool2str(strcasecmp(string{"aasd"}.c_str(),string{"AasD"}.c_str())==0)<<endl;StringCaseInsensetiveCompare cmp;
cout<< bool2str(cmp("A","a"))<<endl;
cout<< bool2str(cmp(string{"Aaaa"},string{"aaaA"}))<<endl;
cout<< bool2str(str_ignoreCase_cmp(string{"Aaaa"},string{"aaaA"}))<<endl;return0;}
Angenommen, Sie suchen nach einer Methode und nicht nach einer bereits existierenden magischen Funktion, gibt es offen gesagt keinen besseren Weg. Wir könnten alle Code-Schnipsel mit cleveren Tricks für begrenzte Zeichensätze schreiben, aber am Ende des Tages müssen Sie die Zeichen irgendwann konvertieren.
Der beste Ansatz für diese Konvertierung besteht darin, dies vor dem Vergleich zu tun. Dies ermöglicht Ihnen ein hohes Maß an Flexibilität bei Codierungsschemata, die Ihr tatsächlicher Vergleichsoperator nicht kennen sollte.
Sie können diese Konvertierung natürlich hinter Ihrer eigenen Zeichenfolgenfunktion oder -klasse 'verbergen', aber Sie müssen die Zeichenfolgen vor dem Vergleich noch konvertieren.
Ich habe eine Version von char_traits ohne Berücksichtigung der Groß- und Kleinschreibung für die Verwendung mit std :: basic_string geschrieben, um einen std :: string zu generieren, bei dem bei Vergleichen, Suchen usw. mit den integrierten std :: basic_string-Elementfunktionen nicht zwischen Groß- und Kleinschreibung unterschieden wird.
Mit anderen Worten, ich wollte so etwas machen.
std::string a ="Hello, World!";
std::string b ="hello, world!";
assert( a == b );
... was std :: string nicht verarbeiten kann. Hier ist die Verwendung meiner neuen char_traits:
std::istring a ="Hello, World!";
std::istring b ="hello, world!";
assert( a == b );
... und hier ist die Implementierung:
/* ---
Case-Insensitive char_traits for std::string's
Use:
To declare a std::string which preserves case but ignores case in comparisons & search,
use the following syntax:
std::basic_string<char, char_traits_nocase<char> > noCaseString;
A typedef is declared below which simplifies this use for chars:
typedef std::basic_string<char, char_traits_nocase<char> > istring;
--- */template<class C>struct char_traits_nocase :public std::char_traits<C>{staticbool eq(const C& c1,const C& c2 ){return::toupper(c1)==::toupper(c2);}staticbool lt(const C& c1,const C& c2 ){return::toupper(c1)<::toupper(c2);}staticint compare(const C* s1,const C* s2,size_t N ){return _strnicmp(s1, s2, N);}staticconstchar* find(const C* s,size_t N,const C& a ){for(size_t i=0; i<N ;++i ){if(::toupper(s[i])==::toupper(a))return s+i ;}return0;}staticbool eq_int_type(const int_type& c1,const int_type& c2 ){return::toupper(c1)==::toupper(c2);}};template<>struct char_traits_nocase<wchar_t>:public std::char_traits<wchar_t>{staticbool eq(constwchar_t& c1,constwchar_t& c2 ){return::towupper(c1)==::towupper(c2);}staticbool lt(constwchar_t& c1,constwchar_t& c2 ){return::towupper(c1)<::towupper(c2);}staticint compare(constwchar_t* s1,constwchar_t* s2,size_t N ){return _wcsnicmp(s1, s2, N);}staticconstwchar_t* find(constwchar_t* s,size_t N,constwchar_t& a ){for(size_t i=0; i<N ;++i ){if(::towupper(s[i])==::towupper(a))return s+i ;}return0;}staticbool eq_int_type(const int_type& c1,const int_type& c2 ){return::towupper(c1)==::towupper(c2);}};typedef std::basic_string<char, char_traits_nocase<char>> istring;typedef std::basic_string<wchar_t, char_traits_nocase<wchar_t>> iwstring;
Dies funktioniert für normale Zeichen, aber nicht für alle Unicode-Zeichen, da die Captitalisierung nicht unbedingt bidirektional ist (es gibt ein gutes Beispiel auf Griechisch, das Sigma beinhaltet, an das ich mich derzeit nicht erinnern kann; so etwas hat zwei Klein- und einen Großbuchstaben , und Sie können keinen richtigen Vergleich so oder so bekommen)
coppro
1
Das ist wirklich der falsche Weg. Die Groß- und Kleinschreibung sollte keine Eigenschaft der Zeichenfolgen selbst sein. Was passiert, wenn dasselbe Zeichenfolgenobjekt Vergleiche zwischen Groß- und Kleinschreibung und Groß- und Kleinschreibung benötigt?
Ferruccio
Wenn die Groß- und Kleinschreibung nicht geeignet ist, "Teil" der Zeichenfolge zu sein, ist die Funktion find () überhaupt nicht vorhanden. Was für Sie wahr sein könnte, und das ist in Ordnung. IMO ist das Beste an C ++, dass es dem Programmierer kein bestimmtes Paradigma aufzwingt. Es ist das, was du willst / brauchst.
John Dibling
Eigentlich denke ich, dass die meisten C ++ - Guru (wie die im Standardkomitee) der Meinung sind, dass es ein Fehler war, find () in std :: basic_string <> zusammen mit vielen anderen Dingen zu setzen, die ebenso gut platziert werden könnten freie Funktionen. Außerdem gibt es einige Probleme beim Einfügen in den Typ.
Andreas Magnusson
Wie andere bereits betont haben, gibt es zwei Hauptprobleme bei dieser Lösung (ironischerweise ist eines die Schnittstelle und das andere die Implementierung ;-)).
Konrad Rudolph
4
Ich habe gute Erfahrungen mit der Verwendung der International Components for Unicode-Bibliotheken gemacht - sie sind äußerst leistungsfähig und bieten Methoden für die Konvertierung, die Unterstützung von Gebietsschemas, das Rendern von Datum und Uhrzeit, die Fallzuordnung (die Sie anscheinend nicht möchten) und die Sortierung . Dies beinhaltet einen Vergleich zwischen Groß- und Kleinschreibung und Akzent (und mehr). Ich habe nur die C ++ - Version der Bibliotheken verwendet, aber sie scheinen auch eine Java-Version zu haben.
Es gibt Methoden, um normalisierte Vergleiche durchzuführen, auf die von @Coincoin verwiesen wird, und sie können sogar das Gebietsschema berücksichtigen - zum Beispiel (und dies ist ein Sortierbeispiel, das nicht streng gleich ist), traditionell auf Spanisch (in Spanien), zwischen denen die Buchstabenkombination "ll" sortiert "l" und "m", also "lz" <"ll" <"ma".
Verwenden Sie diese Option nur zum Vergleich zwischen strcmp()Groß- und Kleinschreibung und / strcmpi()oder stricmp()zum Vergleich zwischen Groß- und Kleinschreibung. Welche sind beide in der Header-Datei<string.h>
Format:
int strcmp(constchar*,constchar*);//for case sensitiveint strcmpi(constchar*,constchar*);//for case insensitive
Verwendungszweck:
string a="apple",b="ApPlE",c="ball";if(strcmpi(a.c_str(),b.c_str())==0)//(if it is a match it will return 0)
cout<<a<<" and "<<b<<" are the same"<<"\n";if(strcmpi(a.c_str(),b.c_str()<0)
cout<<a[0]<<" comes before ball "<<b[0]<<", so "<<a<<" comes before "<<b;
Dies ist die C ++ - Konvention an meiner Universität, aber ich werde sie beim Posten hier berücksichtigen
Rubenjohn
4
stricmp ist eine Microsoft-Erweiterung AFAIK. BSD scheint stattdessen strcasecmp () zu haben.
Zeuge
3
Spät zur Party, aber hier ist eine Variante, die std::localeTürkisch verwendet und damit richtig umgeht:
auto tolower = std::bind1st(
std::mem_fun(&std::ctype<char>::tolower),&std::use_facet<std::ctype<char>>(
std::locale()));
gibt Ihnen einen Funktor, der das aktive Gebietsschema verwendet, um Zeichen in Kleinbuchstaben umzuwandeln, über die Sie dann Zeichenfolgen in Kleinbuchstaben std::transformgenerieren können:
std::string left ="fOo";
transform(left.begin(), left.end(), left.begin(), tolower);
Dies funktioniert auch für wchar_tbasierte Zeichenfolgen.
Nur ein Hinweis zu der Methode, die Sie letztendlich auswählen, falls diese Methode die Verwendung von beinhaltet strcmp , schlagen einige Antworten vor:
strcmpfunktioniert im Allgemeinen nicht mit Unicode-Daten. Im Allgemeinen funktioniert es nicht einmal mit bytebasierten Unicode-Codierungen wie utf-8, da strcmpnur Byte-pro-Byte-Vergleiche durchgeführt werden und in utf-8 codierte Unicode-Codepunkte mehr als 1 Byte benötigen können. Der einzige spezifische Unicode-Fall, der strcmprichtig behandelt wird, ist, wenn eine mit einer bytebasierten Codierung codierte Zeichenfolge nur Codepunkte unter U + 00FF enthält - dann ist der Vergleich von Byte pro Byte ausreichend.
ICU ist eine "vollständige, tragbare Unicode-Bibliothek, die die Industriestandards genau verfolgt". Für das spezifische Problem des Zeichenfolgenvergleichs macht das Kollatierungsobjekt das, was Sie wollen.
Das Mozilla-Projekt hat Mitte 2012 die Intensivstation für die Internationalisierung in Firefox verabschiedet. Hier können Sie die technische Diskussion verfolgen, einschließlich Fragen zu Buildsystemen und Datendateigröße:
Es sieht so aus, als ob die oben genannten Lösungen nicht die Vergleichsmethode verwenden und total erneut implementieren. Hier ist meine Lösung und ich hoffe, sie funktioniert für Sie (sie funktioniert einwandfrei).
Wenn Sie die Boost-Bibliothek nicht verwenden möchten, finden Sie hier eine Lösung, bei der nur der C ++ - Standard-Io-Header verwendet wird.
#include<iostream>struct iequal
{booloperator()(int c1,int c2)const{// case insensitive comparison of two characters.return std::toupper(c1)== std::toupper(c2);}};bool iequals(const std::string& str1,const std::string& str2){// use std::equal() to compare range of characters using the functor above.return std::equal(str1.begin(), str1.end(), str2.begin(), iequal());}int main(void){
std::string str_1 ="HELLO";
std::string str_2 ="hello";if(iequals(str_1,str_2)){
std::cout<<"String are equal"<<std::endl;}else{
std::cout<<"String are not equal"<<std::endl;}return0;}
Ich glaube, std :: toupper befindet sich in #include <cctype>. Möglicherweise müssen Sie es einschließen.
David Ledger
Wenn Sie eine globale Version wie diese :: toupper verwenden, müssen Sie möglicherweise <ctype> nicht einschließen, da es vermutlich zwei Versionen c-Version und c ++ - Version mit Gebietsschema gibt. Verwenden Sie also besser die globale Version ":: toupper ()"
HaSeeB MiR
Diese Lösung schlägt fehl, wenn eine der Zeichenfolgen leer ist: "" - gibt in diesem Fall true zurück, wenn false zurückgegeben werden soll
ekkis
0
Wenn Sie eine Quellzeichenfolge häufiger mit anderen Zeichenfolgen vergleichen müssen, besteht eine elegante Lösung darin, Regex zu verwenden.
std::wstring first = L"Test";
std::wstring second = L"TEST";
std::wregex pattern(first, std::wregex::icase);bool isEqual = std::regex_match(second, pattern);
Versuchte dies, aber kompilierte Fehler: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing
schlechte Idee. Es ist die schlechteste Lösung.
Behrouz.M
Dies ist keine gute Lösung, aber selbst wenn Sie sie verwenden möchten, benötigen Sie ein L vor Ihren breitesten Konstanten, z. B. L "TEST"
Celticminstrel
Wäre schön, wenn jemand erklären könnte, warum es die schlechteste Lösung ist. Wegen Leistungsproblemen? Das Erstellen des regulären Ausdrucks ist teuer, aber danach sollte der Vergleich sehr schnell sein.
Smibe
Es ist verwendbar und portabel. Das Hauptproblem besteht darin, dass es zunächst keine Zeichen enthalten kann, die Regex verwendet. Aus diesem Grund kann es nicht als allgemeiner Zeichenfolgenvergleich verwendet werden. Es wird auch langsamer sein, es gibt eine Flagge, damit es so funktioniert, wie es smibe sagt, aber es kann immer noch nicht als allgemeine Funktion verwendet werden.
Ben
0
Eine einfache Möglichkeit, zwei Zeichenfolgen in c ++ (für Windows getestet) zu vergleichen, ist die Verwendung von _stricmp
// Case insensitive (could use equivalent _stricmp)
result = _stricmp( string1, string2 );
Wenn Sie mit std :: string verwenden möchten, ein Beispiel:
std::string s1 = string("Hello");if( _stricmp(s1.c_str(),"HELLO")==0)
std::cout <<"The string are equals.";
Zusätzlich zu dieser Antwort lohnt es sich, stackoverflow.com/a/12414441/95309 zu lesen , da es a) eine C-Funktion und b) angeblich nicht portabel ist.
Claus Jørgensen
Was #include brauchen wir, damit das funktioniert?
bool insensitive_c_compare(char A,char B){staticchar mid_c =('Z'+'a')/2+'Z';staticchar up2lo ='A'-'a';/// the offset between upper and lowersif('a'>= A and A >='z'or'A'>= A and'Z'>= A)if('a'>= B and B >='z'or'A'>= B and'Z'>= B)/// check that the character is infact a letter/// (trying to turn a 3 into an E would not be pretty!){if(A > mid_c and B > mid_c or A < mid_c and B < mid_c){return A == B;}else{if(A > mid_c)
A = A -'a'+'A';if(B > mid_c)/// convert all uppercase letters to a lowercase ones
B = B -'a'+'A';/// this could be changed to B = B + up2lo;return A == B;}}}
Dies könnte wahrscheinlich viel effizienter gemacht werden, aber hier ist eine sperrige Version mit all ihren Teilen.
nicht allzu tragbar, funktioniert aber gut mit allem, was sich auf meinem Computer befindet (keine Ahnung, ich bin von Bildern, nicht von Worten)
Dies ist keine Unicode-Unterstützung, wie in der Frage gestellt.
Behrouz.M
Dies unterstützt keine nicht englischen Zeichensätze.
Robert Andrzejuk
-3
Eine einfache Möglichkeit, Zeichenfolgen zu vergleichen, die sich nur durch Kleinbuchstaben und Großbuchstaben unterscheiden, ist ein ASCII-Vergleich. Alle Groß- und Kleinbuchstaben unterscheiden sich in der ASCII-Tabelle um 32 Bit. Mit diesen Informationen haben wir Folgendes ...
for(int i =0; i < string2.length(); i++){if(string1[i]== string2[i]||int(string1[i])==int(string2[j])+32||int(string1[i])==int(string2[i])-32){
count++;continue;}else{break;}if(count == string2.length()){//then we have a match}}
std::stricmp
. Ansonsten lesen Sie, was Herb zu sagen hat .strcasecmp
die nicht Teil des Standards ist und in mindestens einem gemeinsamen Compiler fehlt.Antworten:
Boost enthält hierfür einen praktischen Algorithmus:
quelle
Nutzen Sie den Standard
char_traits
. Denken Sie daran, dass astd::string
tatsächlich ein typedef fürstd::basic_string<char>
oder expliziter iststd::basic_string<char, std::char_traits<char> >
. Derchar_traits
Typ beschreibt, wie Zeichen verglichen werden, wie sie kopiert werden, wie sie umgewandelt werden usw. Alles, was Sie tun müssen, ist, eine neue Zeichenfolge zu überschreibenbasic_string
und sie mit Ihrer eigenen benutzerdefinierten Zeichenfolge zu versehen, bei derchar_traits
Groß- und Kleinschreibung nicht berücksichtigt wird.Die Details sind auf Guru der Woche Nummer 29 .
quelle
typedef std::basic_string<char, ci_char_traits<char> > istring
nichttypedef std::basic_string<char, std::char_traits<char> > string
.Das Problem mit Boost ist, dass Sie sich mit Boost verbinden und von Boost abhängen müssen. In einigen Fällen nicht einfach (zB Android).
Die Verwendung von char_traits bedeutet, dass bei all Ihren Vergleichen die Groß- und Kleinschreibung nicht berücksichtigt wird. Dies ist normalerweise nicht das, was Sie möchten.
Das sollte ausreichen. Es sollte einigermaßen effizient sein. Behandelt jedoch keinen Unicode oder ähnliches.
Update: Bonus C ++ 14 Version (
#include <algorithm>
):quelle
Wenn Sie sich auf einem POSIX-System befinden, können Sie strcasecmp verwenden . Diese Funktion ist jedoch weder Teil von Standard C noch unter Windows verfügbar. Dadurch wird ein Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung für 8-Bit-Zeichen durchgeführt, sofern das Gebietsschema POSIX ist. Wenn das Gebietsschema nicht POSIX ist, sind die Ergebnisse undefiniert (daher wird möglicherweise ein lokalisierter Vergleich durchgeführt oder nicht). Ein Breitzeichenäquivalent ist nicht verfügbar.
Andernfalls haben viele historische C-Bibliotheksimplementierungen die Funktionen stricmp () und strnicmp (). Visual C ++ unter Windows hat all dies umbenannt, indem ihnen ein Unterstrich vorangestellt wurde, da sie nicht Teil des ANSI-Standards sind. Auf diesem System heißen sie also _stricmp oder _strnicmp . Einige Bibliotheken verfügen möglicherweise auch über Breitzeichen- oder Multibyte-äquivalente Funktionen (normalerweise z. B. wcsicmp, mbcsicmp usw.).
C und C ++ kennen beide Internationalisierungsprobleme weitgehend nicht, daher gibt es keine gute Lösung für dieses Problem, außer die Verwendung einer Bibliothek eines Drittanbieters. Schauen Sie sich IBM ICU (International Components for Unicode) an, wenn Sie eine robuste Bibliothek für C / C ++ benötigen. Die Intensivstation ist sowohl für Windows- als auch für Unix-Systeme geeignet.
quelle
Sprechen Sie über einen dummen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung oder einen vollständig normalisierten Unicode-Vergleich?
Bei einem dummen Vergleich werden keine Zeichenfolgen gefunden, die möglicherweise gleich, aber nicht binär gleich sind.
Beispiel:
Sind alle gleichwertig, haben aber auch unterschiedliche binäre Darstellungen.
Die Unicode-Normalisierung sollte jedoch obligatorisch sein, insbesondere wenn Sie Hangul, Thaï und andere asiatische Sprachen unterstützen möchten.
Außerdem hat IBM die am meisten optimierten Unicode-Algorithmen patentiert und öffentlich zugänglich gemacht. Sie pflegen auch eine Implementierung: IBM ICU
quelle
boost :: iequals ist im Fall von string nicht mit utf-8 kompatibel. Sie können boost :: locale verwenden .
quelle
Mein erster Gedanke für eine Nicht-Unicode-Version war, so etwas zu tun:
quelle
Sie können
strcasecmp
unter Unix oderstricmp
Windows verwenden.Eine Sache, die bisher nicht erwähnt wurde, ist, dass es nützlich ist, zuerst die Länge der beiden Zeichenfolgen zu vergleichen, wenn Sie stl-Zeichenfolgen mit diesen Methoden verwenden, da diese Informationen Ihnen bereits in der Zeichenfolgenklasse zur Verfügung stehen. Dies könnte verhindern, dass der kostspielige Zeichenfolgenvergleich durchgeführt wird, wenn die beiden Zeichenfolgen, die Sie vergleichen, überhaupt nicht gleich lang sind.
quelle
Visual C ++ - Zeichenfolgenfunktionen, die Unicode unterstützen: http://msdn.microsoft.com/en-us/library/cc194799.aspx
die, die Sie wahrscheinlich suchen, ist
_wcsnicmp
quelle
Ich versuche, eine gute Antwort aus allen Beiträgen zusammenzustellen, also hilf mir, diese zu bearbeiten:
Hier ist eine Methode, um dies zu tun, obwohl sie die Zeichenfolgen transformiert und nicht Unicode-freundlich ist, sollte sie portabel sein, was ein Plus ist:
Nach dem, was ich gelesen habe, ist dies portabler als stricmp (), da stricmp () nicht Teil der Standardbibliothek ist, sondern nur von den meisten Compiler-Anbietern implementiert wird.
Um eine wirklich Unicode-freundliche Implementierung zu erhalten, müssen Sie anscheinend die Standardbibliothek verlassen. Eine gute Bibliothek von Drittanbietern ist die IBM ICU (International Components for Unicode).
Auch boost :: iequals bietet ein ziemlich gutes Dienstprogramm für diese Art von Vergleich.
quelle
transform
die gesamte Zeichenfolge vor dem VergleichSie können den obigen Code in C ++ 14 verwenden, wenn Sie nicht in der Lage sind, Boost zu verwenden. Sie müssen
std::towlower
für breite Zeichen verwenden.quelle
str1.size() == str2.size() &&
der Vorderseite ein hinzufügen , damit die Grenzen nicht überschritten werden, wenn str2 ein Präfix von str1 ist.Der Boost.String Bibliothek verfügt über zahlreiche Algorithmen für Vergleiche ohne Berücksichtigung der Groß- und Kleinschreibung usw.
Sie könnten Ihre eigenen implementieren, aber warum sollten Sie sich die Mühe machen, wenn dies bereits geschehen ist?
quelle
Zu Ihrer Information,
strcmp()
undstricmp()
sind anfällig für Pufferüberlauf, da sie nur verarbeitet werden, bis sie einen Null-Terminator erreichen. Es ist sicherer zu bedienen_strncmp()
und_strnicmp()
.quelle
stricmp()
undstrnicmp()
sind nicht Teil des POSIX-Standards :-( Wie auch immer Sie findenstrcasecmp()
könnenstrcasecmp_l()
,strncasecmp()
undstrncasecmp_l()
im POSIX-Headerstrings.h
:-) siehe opengroup.orgSiehe
std::lexicographical_compare
:Demo
quelle
std::tolower
funktioniert nur, wenn das Zeichen ASCII-codiert ist. Es gibt keine solche Garantie fürstd::string
- so kann es leicht undefiniertes Verhalten sein.Für meine grundlegenden Anforderungen zum Vergleichen von Zeichenfolgen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird, möchte ich keine externe Bibliothek verwenden, und ich möchte auch keine separate Zeichenfolgenklasse mit Merkmalen, bei denen die Groß- und Kleinschreibung nicht berücksichtigt wird und die nicht mit allen anderen Zeichenfolgen kompatibel ist.
Was ich mir also ausgedacht habe, ist Folgendes:
Eine einfache Funktion mit einer Überladung für char und einer anderen für whar_t. Verwendet nichts, was nicht dem Standard entspricht, sollte also auf jeder Plattform in Ordnung sein.
Der Gleichheitsvergleich berücksichtigt keine Probleme wie Codierung mit variabler Länge und Unicode-Normalisierung, aber basic_string unterstützt das sowieso nicht und ist normalerweise kein Problem.
In Fällen, in denen eine ausgefeiltere lexikografische Manipulation von Text erforderlich ist, müssen Sie einfach eine Drittanbieter-Bibliothek wie Boost verwenden, was zu erwarten ist.
quelle
Kurz und nett. Keine anderen Abhängigkeiten als erweiterte std C lib.
gibt true zurück , wenn
str1
undstr2
gleich sind.strcasecmp
kann nicht existieren, es könnte Analoga gebenstricmp
,strcmpi
usw.Beispielcode:
Ausgabe:
quelle
stricmp
,strcmpi
,strcasecmp
, Danke usw.. Nachricht bearbeitet.cout << boolalpha
anstelle von my,bool2str
weil es Bool implizit in Zeichen für Stream konvertiert.Dies ohne Boost zu tun, kann erreicht werden, indem der C-String-Zeiger mit
c_str()
und verwendet wirdstrcasecmp
:quelle
Angenommen, Sie suchen nach einer Methode und nicht nach einer bereits existierenden magischen Funktion, gibt es offen gesagt keinen besseren Weg. Wir könnten alle Code-Schnipsel mit cleveren Tricks für begrenzte Zeichensätze schreiben, aber am Ende des Tages müssen Sie die Zeichen irgendwann konvertieren.
Der beste Ansatz für diese Konvertierung besteht darin, dies vor dem Vergleich zu tun. Dies ermöglicht Ihnen ein hohes Maß an Flexibilität bei Codierungsschemata, die Ihr tatsächlicher Vergleichsoperator nicht kennen sollte.
Sie können diese Konvertierung natürlich hinter Ihrer eigenen Zeichenfolgenfunktion oder -klasse 'verbergen', aber Sie müssen die Zeichenfolgen vor dem Vergleich noch konvertieren.
quelle
Ich habe eine Version von char_traits ohne Berücksichtigung der Groß- und Kleinschreibung für die Verwendung mit std :: basic_string geschrieben, um einen std :: string zu generieren, bei dem bei Vergleichen, Suchen usw. mit den integrierten std :: basic_string-Elementfunktionen nicht zwischen Groß- und Kleinschreibung unterschieden wird.
Mit anderen Worten, ich wollte so etwas machen.
... was std :: string nicht verarbeiten kann. Hier ist die Verwendung meiner neuen char_traits:
... und hier ist die Implementierung:
quelle
Ich habe gute Erfahrungen mit der Verwendung der International Components for Unicode-Bibliotheken gemacht - sie sind äußerst leistungsfähig und bieten Methoden für die Konvertierung, die Unterstützung von Gebietsschemas, das Rendern von Datum und Uhrzeit, die Fallzuordnung (die Sie anscheinend nicht möchten) und die Sortierung . Dies beinhaltet einen Vergleich zwischen Groß- und Kleinschreibung und Akzent (und mehr). Ich habe nur die C ++ - Version der Bibliotheken verwendet, aber sie scheinen auch eine Java-Version zu haben.
Es gibt Methoden, um normalisierte Vergleiche durchzuführen, auf die von @Coincoin verwiesen wird, und sie können sogar das Gebietsschema berücksichtigen - zum Beispiel (und dies ist ein Sortierbeispiel, das nicht streng gleich ist), traditionell auf Spanisch (in Spanien), zwischen denen die Buchstabenkombination "ll" sortiert "l" und "m", also "lz" <"ll" <"ma".
quelle
Verwenden Sie diese Option nur zum Vergleich zwischen
strcmp()
Groß- und Kleinschreibung und /strcmpi()
oderstricmp()
zum Vergleich zwischen Groß- und Kleinschreibung. Welche sind beide in der Header-Datei<string.h>
Format:
Verwendungszweck:
Ausgabe
Apfel und ApPlE sind gleich
a kommt vor b, also kommt Apfel vor Ball
quelle
Spät zur Party, aber hier ist eine Variante, die
std::locale
Türkisch verwendet und damit richtig umgeht:gibt Ihnen einen Funktor, der das aktive Gebietsschema verwendet, um Zeichen in Kleinbuchstaben umzuwandeln, über die Sie dann Zeichenfolgen in Kleinbuchstaben
std::transform
generieren können:Dies funktioniert auch für
wchar_t
basierte Zeichenfolgen.quelle
Nur ein Hinweis zu der Methode, die Sie letztendlich auswählen, falls diese Methode die Verwendung von beinhaltet
strcmp
, schlagen einige Antworten vor:strcmp
funktioniert im Allgemeinen nicht mit Unicode-Daten. Im Allgemeinen funktioniert es nicht einmal mit bytebasierten Unicode-Codierungen wie utf-8, dastrcmp
nur Byte-pro-Byte-Vergleiche durchgeführt werden und in utf-8 codierte Unicode-Codepunkte mehr als 1 Byte benötigen können. Der einzige spezifische Unicode-Fall, derstrcmp
richtig behandelt wird, ist, wenn eine mit einer bytebasierten Codierung codierte Zeichenfolge nur Codepunkte unter U + 00FF enthält - dann ist der Vergleich von Byte pro Byte ausreichend.quelle
Ab Anfang 2013 ist das von IBM gepflegte ICU-Projekt eine ziemlich gute Antwort darauf.
http://site.icu-project.org/
ICU ist eine "vollständige, tragbare Unicode-Bibliothek, die die Industriestandards genau verfolgt". Für das spezifische Problem des Zeichenfolgenvergleichs macht das Kollatierungsobjekt das, was Sie wollen.
Das Mozilla-Projekt hat Mitte 2012 die Intensivstation für die Internationalisierung in Firefox verabschiedet. Hier können Sie die technische Diskussion verfolgen, einschließlich Fragen zu Buildsystemen und Datendateigröße:
quelle
Es sieht so aus, als ob die oben genannten Lösungen nicht die Vergleichsmethode verwenden und total erneut implementieren. Hier ist meine Lösung und ich hoffe, sie funktioniert für Sie (sie funktioniert einwandfrei).
quelle
Wenn Sie die Boost-Bibliothek nicht verwenden möchten, finden Sie hier eine Lösung, bei der nur der C ++ - Standard-Io-Header verwendet wird.
quelle
Wenn Sie eine Quellzeichenfolge häufiger mit anderen Zeichenfolgen vergleichen müssen, besteht eine elegante Lösung darin, Regex zu verwenden.
quelle
error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Eine einfache Möglichkeit, zwei Zeichenfolgen in c ++ (für Windows getestet) zu vergleichen, ist die Verwendung von _stricmp
Wenn Sie mit std :: string verwenden möchten, ein Beispiel:
Weitere Informationen finden Sie hier: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx
quelle
Dies könnte wahrscheinlich viel effizienter gemacht werden, aber hier ist eine sperrige Version mit all ihren Teilen.
nicht allzu tragbar, funktioniert aber gut mit allem, was sich auf meinem Computer befindet (keine Ahnung, ich bin von Bildern, nicht von Worten)
quelle
Eine einfache Möglichkeit, Zeichenfolgen zu vergleichen, die sich nur durch Kleinbuchstaben und Großbuchstaben unterscheiden, ist ein ASCII-Vergleich. Alle Groß- und Kleinbuchstaben unterscheiden sich in der ASCII-Tabelle um 32 Bit. Mit diesen Informationen haben wir Folgendes ...
quelle