Porównanie ciągów znaków bez rozróżniania wielkości liter w C ++ [zamknięte]
373
Jaki jest najlepszy sposób na porównywanie ciągów znaków bez rozróżniania wielkości liter w C ++ bez przekształcania łańcucha na wszystkie wielkie lub małe litery?
Wskaż, czy metody są przyjazne dla Unicode i jak są przenośne.
@ [Adam] (# 11679): Chociaż ten wariant jest dobry pod względem użyteczności, jest zły pod względem wydajności, ponieważ tworzy niepotrzebne kopie. Mogę coś przeoczyć, ale uważam, że najlepszym (innym niż Unicode) sposobem jest użycie std::stricmp. W przeciwnym razie przeczytaj, co ma do powiedzenia Herb .
Konrad Rudolph
W c zwykle jeden zmuszony był dotknąć całego struny, a następnie porównać w ten sposób - lub rzucić własne porównanie: P
@ Mσᶎ to pytanie również ma tę odpowiedź, z ważnym zastrzeżeniem, które strcasecmpnie jest częścią standardu i brakuje go w co najmniej jednym wspólnym kompilatorze.
Mark Ransom,
Odpowiedzi:
317
Boost zawiera przydatny algorytm do tego:
#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}
Nie, ponieważ UTF-8 pozwala na kodowanie identycznych ciągów za pomocą różnych kodów binarnych, ze względu na akcenty,
kombinacje
10
@ vy32 To absolutnie niepoprawne! Kombinacje UTF-8 wzajemnie się wykluczają. Musi zawsze używać możliwie najkrótszej reprezentacji, jeśli nie, jest to zniekształcona sekwencja UTF-8 lub punkt kodowy, który należy traktować ostrożnie.
Wiz
48
@Wiz, ignorujesz problem normalizacji ciągów Unicode. ñ może być reprezentowane jako połączenie ˜, po którym następuje n lub znak ñ. Przed porównaniem należy użyć normalizacji ciągów Unicode. Zapoznaj się z raportem technicznym Unicode nr 15, unicode.org/reports/tr15
Skorzystaj ze standardu char_traits. Przypomnijmy, że std::stringw rzeczywistości jest typedef dla std::basic_string<char>lub bardziej jawnie std::basic_string<char, std::char_traits<char> >. Ten char_traitstyp opisuje, w jaki sposób znaki się porównują, jak kopiują, jak rzutują itp. Wystarczy, że napiszesz nowy ciąg znaków basic_stringi nadasz mu własny zwyczaj, char_traitsktóry porównuje wielkość liter bez rozróżnienia.
O ile wiem z własnych eksperymentów, powoduje to, że twój nowy typ łańcucha jest niezgodny ze std :: string.
Zan Lynx,
8
Oczywiście, że tak - dla własnego dobra. Ciąg bez rozróżniania wielkości liter to coś innego: typedef std::basic_string<char, ci_char_traits<char> > istringnie typedef std::basic_string<char, std::char_traits<char> > string.
Andreas Spindler
232
„Wszystko, co musisz zrobić ...”
Tim MB
3
@Nathan prawdopodobnie używa kompilatora, który jest w stanie wykonać podstawowe CSE na kodzie ...
The Paramagnetic Croissant
17
Wszelkie konstrukcje językowe, które wymuszają takie szaleństwo w tym trywialnym przypadku, powinny i mogą zostać porzucone bez żalu.
Erik Aronesty
86
Problem z doładowaniem polega na tym, że musisz się połączyć i polegać na doładowaniu. W niektórych przypadkach nie jest to łatwe (np. Android).
A używanie char_traits oznacza wszystko porównania nie uwzględniają wielkości liter, co zwykle nie jest tym, czego chcesz.
To powinno wystarczyć. Powinien być dość wydajny. Nie obsługuje jednak Unicode ani nic takiego.
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;}
Aktualizacja: Bonusowa wersja C ++ 14 ( #include <algorithm>):
W rzeczywistości biblioteka znaków doładowania jest biblioteką zawierającą tylko nagłówki, więc nie ma potrzeby łączenia z niczym. Możesz także użyć narzędzia „bcp” programu boost, aby skopiować tylko nagłówki ciągów do drzewa źródłowego, więc nie musisz wymagać pełnej biblioteki boost.
Gretchen
Ach, nie wiedziałem o bcp, wygląda to naprawdę przydatne. Dzięki za informację!
Timmmm
9
Dobrze wiedzieć, że jest to prosta i nie zależna od wersji wersja.
Deqing
2
@Anna biblioteka tekstowa doładowania musi zostać zbudowana i połączona. Korzysta z IBM ICU.
Behrouz.M
Dostępne również z C ++ 11
martian
58
Jeśli korzystasz z systemu POSIX, możesz użyć strcasecmp . Ta funkcja nie jest jednak częścią standardowego C i nie jest dostępna w systemie Windows. Spowoduje to porównanie bez rozróżniania wielkości liter na 8-bitowych znakach, o ile ustawieniem narodowym jest POSIX. Jeśli ustawieniami narodowymi nie jest POSIX, wyniki są niezdefiniowane (więc może wykonać zlokalizowane porównanie lub nie). Odpowiednik szerokich znaków nie jest dostępny.
W przeciwnym razie duża liczba historycznych implementacji biblioteki C ma funkcje stricmp () i strnicmp (). Visual C ++ w systemie Windows przemianował je wszystkie, poprzedzając je znakiem podkreślenia, ponieważ nie są one częścią standardu ANSI, więc w tym systemie nazywane są _stricmp lub _strnicmp . Niektóre biblioteki mogą mieć także funkcje równoważne szerokim znakom lub wielobajtom (zwykle nazywane np. Wcsicmp, mbcsicmp i tak dalej).
Zarówno C, jak i C ++ są w dużej mierze nieświadomi problemów związanych z internacjonalizacją, więc nie ma dobrego rozwiązania tego problemu, z wyjątkiem korzystania z biblioteki innej firmy. Sprawdź IBM ICU (International Components for Unicode), jeśli potrzebujesz solidnej biblioteki dla C / C ++. ICU jest przeznaczony zarówno dla systemów Windows, jak i Unix.
Możesz używać w systemie strcasecmpUnix lub stricmpWindows.
Jedną z rzeczy, o których nie wspomniano do tej pory, jest to, że jeśli używasz ciągów stl z tymi metodami, warto najpierw porównać długość tych dwóch ciągów, ponieważ te informacje są już dostępne w klasie ciągów. Może to uniemożliwić wykonanie kosztownego porównania ciągów, jeśli dwa porównywane ciągi nie będą w ogóle nawet tej samej długości.
Skoro określenie długości łańcucha polega na iteracji nad każdym znakiem w łańcuchu i porównaniu go z wartością 0, to czy naprawdę jest tak duża różnica między tym a samym porównywaniem łańcuchów od razu? Wydaje mi się, że masz lepszą lokalizację pamięci w przypadku, gdy oba ciągi się nie zgadzają, ale prawdopodobnie prawie 2-krotnie czas działania w przypadku dopasowania.
To zabawny fakt, ale nie ma tu większego znaczenia. Zarówno strcasecmp (), jak i stricmp () pobierają nieekorowane ciągi C, więc nie jest zaangażowany ciąg std :: string.
wszechstronność
3
Te metody zwrócą -1, jeśli porównasz „a” vs „ab”. Długości są różne, ale „a” występuje przed „ab”. Tak więc zwykłe porównanie długości nie jest możliwe, jeśli rozmówcy zależy na zamówieniu.
Z tego, co przeczytałem, jest on bardziej przenośny niż stricmp (), ponieważ stricmp () nie jest tak naprawdę częścią biblioteki std, ale jest implementowany tylko przez większość dostawców kompilatorów.
„... po co męczyć się, gdy już zostało to zrobione?” - co jeśli nie używasz wzmocnienia? OP nie miał tagu z pytaniem.
jww
11
FYI strcmp()i stricmp()są podatne na przepełnienie bufora, ponieważ przetwarzają tylko, dopóki nie osiągną zerowego terminatora. Jest bezpieczniejszy w użyciu _strncmp()i _strnicmp().
To prawda, chociaż przeciążenie bufora jest znacznie mniej niebezpieczne niż zastąpienie bufora.
Adam Rosenfield,
4
stricmp()i strnicmp()nie są częścią standardu POSIX :-( Jednak można znaleźć strcasecmp(), strcasecmp_l(), strncasecmp()i strncasecmp_l()POSIX nagłówku strings.h:-) zobaczyć opengroup.org
olibre
2
@AdamRosenfield „gorsze” zależy od kontekstu. W bezpieczeństwie czasami nadrzędnym celem nadpisania jest przemyślenie.
Ta metoda jest potencjalnie niebezpieczna i nieprzenośna. std::tolowerdziała tylko wtedy, gdy znak jest zakodowany w ASCII. Nie ma takiej gwarancji na std::string- więc może być łatwo niezdefiniowanym zachowaniem.
plasmacel
@plasmacel Następnie użyj funkcji, która działa z innymi kodowaniami.
Brian Rodriguez,
9
Ze względu na moje podstawowe potrzeby porównywania ciągów bez rozróżniania wielkości liter wolę nie używać biblioteki zewnętrznej, ani też nie chcę osobnej klasy ciągów z cechami bez rozróżniania wielkości liter, która jest niezgodna ze wszystkimi innymi ciągami.
Prosta funkcja z jednym przeciążeniem dla char i innym dla whar_t. Nie używa niczego niestandardowego, więc powinno być dobrze na każdej platformie.
Porównanie równości nie bierze pod uwagę takich kwestii, jak kodowanie o zmiennej długości i normalizacja Unicode, ale basic_string nie obsługuje tego, o czym jestem świadomy, i zwykle nie jest to problem.
W przypadkach, w których wymagana jest bardziej wyrafinowana leksykograficzna manipulacja tekstem, wystarczy użyć biblioteki innej firmy, takiej jak Boost, czego należy się spodziewać.
Prawdopodobnie możesz zrobić tę jedną funkcję, jeśli utworzysz szablon i użyjesz podstawowego łańcucha <T> zamiast osobnych wersji łańcucha / łańcucha?
uliwitness
2
Jak szablon pojedynczej funkcji wywołałby touppera lub towuppera bez uciekania się do specjalizacji lub makr, przeciążenie funkcji wydaje się prostszą i bardziej odpowiednią implementacją niż jedno z nich.
Neutrino
9
Krótko i miło. Żadnych innych zależności, oprócz rozszerzonej biblioteki std C.
strcasecmp(str1.c_str(), str2.c_str())==0
zwraca true, jeśli str1i str2są równe.
strcasecmpnie może istnieć, nie może być analogi stricmp, strcmpiitp
Przykładowy kod:
#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;}
Zakładając, że szukasz metody, a nie magicznej funkcji, która już istnieje, szczerze mówiąc, nie ma lepszego sposobu. Wszyscy moglibyśmy pisać fragmenty kodu za pomocą sprytnych sztuczek dla ograniczonych zestawów znaków, ale pod koniec dnia w którymś momencie musisz przekonwertować znaki.
Najlepszym podejściem do tej konwersji jest zrobienie tego przed porównaniem. Zapewnia to dużą elastyczność, jeśli chodzi o schematy kodowania, których faktyczny operator porównania powinien być nieświadomy.
Możesz oczywiście „ukryć” tę konwersję za własną funkcją lub klasą łańcuchową, ale przed porównaniem wciąż musisz przekonwertować łańcuchy.
Napisałem rozróżniającą wielkość liter wersję char_traits do użycia ze std :: basic_string w celu wygenerowania std :: string, który nie rozróżnia wielkości liter podczas wykonywania porównań, wyszukiwania itp. Za pomocą wbudowanych funkcji członkowskich std :: basic_string.
Innymi słowy, chciałem zrobić coś takiego.
std::string a ="Hello, World!";
std::string b ="hello, world!";
assert( a == b );
... z którymi std :: string nie może sobie poradzić. Oto użycie moich nowych char_traits:
std::istring a ="Hello, World!";
std::istring b ="hello, world!";
assert( a == b );
... a oto implementacja:
/* ---
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;
Działa to dla zwykłych znaków, ale nie działa dla wszystkich znaków Unicode, ponieważ kapitalizacja niekoniecznie musi być dwukierunkowa (istnieje dobry przykład w języku greckim dotyczący sigmy, którego teraz nie pamiętam; coś takiego ma dwie małe i jedną wielką literę , i tak nie można uzyskać właściwego porównania)
coppro
1
To naprawdę niewłaściwy sposób. Rozróżnianie wielkości liter nie powinno być własnością samych ciągów znaków. Co dzieje się, gdy ten sam ciąg znaków wymaga zarówno rozróżniania wielkości liter, jak i rozróżniania wielkości liter?
Ferruccio
Jeśli rozróżnianie wielkości liter nie jest właściwe, aby być „częścią” ciągu, wówczas funkcja find () w ogóle nie jest. Co dla ciebie może być prawdą i to jest w porządku. IMO największą zaletą C ++ jest to, że nie wymusza on określonego paradygmatu na programatorze. To jest to, czego chcesz / potrzebujesz.
John Dibling,
Właściwie uważam, że większość guru z C ++ (jak ci z komitetu standardów) zgadza się, że błędem było umieszczenie find () w std :: basic_string <> wraz z całą masą innych rzeczy, które równie dobrze można umieścić w darmowe funkcje. Poza tym istnieją pewne problemy z umieszczeniem tego typu.
Andreas Magnusson,
Jak zauważyli inni, w tym rozwiązaniu są dwie główne rzeczy złe (jak na ironię, jedna to interfejs, a druga implementacja ;-)).
Konrad Rudolph,
4
Mam duże doświadczenie w korzystaniu z bibliotek International Components for Unicode - są one niezwykle wydajne i zapewniają metody konwersji, obsługę ustawień regionalnych, renderowanie daty i godziny, mapowanie wielkości liter (których nie chcesz) oraz sortowanie , który obejmuje porównanie bez rozróżniania wielkości liter i akcentów (i więcej). Użyłem tylko bibliotek C ++, ale wydaje się, że mają również wersję Java.
Istnieją metody przeprowadzania znormalizowanych porównań, o których mowa w @Coincoin, i mogą nawet uwzględniać ustawienia regionalne - na przykład (i ten przykład sortowania, nie ściśle równości), tradycyjnie w języku hiszpańskim (w Hiszpanii), kombinacja liter „ll” sortuje między „l” i „m”, więc „lz” <„ll” <„ma”.
Wystarczy użyć do rozróżniania wielkości liter strcmp()i / strcmpi()lub bez stricmp()rozróżniania wielkości liter. Które są w pliku nagłówkowym<string.h>
format:
int strcmp(constchar*,constchar*);//for case sensitiveint strcmpi(constchar*,constchar*);//for case insensitive
Stosowanie:
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;
Oddaj głos, ponieważ nie jest to sposób na robienie rzeczy w C ++.
Thomas Daugaard
To konwencja c ++ na moim uniwersytecie, ale będę o tym pamiętać,
pisząc
4
stricmp to rozszerzenie Microsoft AFAIK. BSD wydaje się mieć zamiast tego strcasecmp ().
uliwitness
3
Późno na imprezę, ale tutaj jest wariant, który wykorzystuje std::locale, a zatem poprawnie obsługuje turecki:
auto tolower = std::bind1st(
std::mem_fun(&std::ctype<char>::tolower),&std::use_facet<std::ctype<char>>(
std::locale()));
daje funktor, który wykorzystuje aktywne ustawienia regionalne do konwersji znaków na małe litery, których można następnie użyć std::transformdo wygenerowania ciągów małych liter:
std::string left ="fOo";
transform(left.begin(), left.end(), left.begin(), tolower);
Działa to również w przypadku wchar_tciągów opartych.
Tylko uwaga na temat jakiejkolwiek metody, którą ostatecznie wybierzesz, jeśli ta metoda obejmuje użycie strcmp , niektóre odpowiedzi sugerują:
strcmpogólnie nie działa z danymi Unicode. Ogólnie rzecz biorąc, nie działa nawet z kodowaniem Unicode opartym na bajtach, takim jak utf-8, ponieważ strcmptylko porównania bajt na bajt i punkty kodu Unicode zakodowane w utf-8 mogą zająć więcej niż 1 bajt. Jedynym konkretnym przypadkiem strcmppoprawnie obsługującym przypadek Unicode jest sytuacja, gdy łańcuch zakodowany za pomocą kodowania bajtowego zawiera tylko punkty kodowe poniżej U + 00FF - wtedy wystarczy porównanie bajtów na bajt.
ICU to „kompletna, przenośna biblioteka Unicode, która ściśle śledzi standardy branżowe”. W przypadku konkretnego problemu porównywania ciągów obiekt Collation robi to, co chcesz.
Projekt Mozilla przyjął ICU do internacjonalizacji w Firefoksie w połowie 2012 roku; możesz śledzić dyskusję inżynierską, w tym kwestie dotyczące systemów kompilacji i rozmiaru pliku danych, tutaj:
Wygląda na to, że powyższe rozwiązania nie używają metody porównywania i nie wdrażają ponownie sumy, więc oto moje rozwiązanie i mam nadzieję, że zadziała dla ciebie (działa dobrze).
Jeśli nie chcesz używać biblioteki Boost, oto rozwiązanie, używając tylko standardowego nagłówka io C ++.
#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;}
Uważam, że std :: toupper jest w #include <cctype>, być może trzeba go dołączyć.
David Ledger
Jeśli użyjesz wersji globalnej takiej jak ta :: toupper, może nie być konieczne dołączenie <typu>, ponieważ są dwie wersje wersja c i wersja c ++ z ustawieniami narodowymi. Lepiej więc użyć wersji globalnej „:: toupper ()”
HaSeeB MiR
to rozwiązanie zawodzi, gdy jeden z ciągów znaków jest pusty: „” - zwraca true w tym przypadku, gdy powinien zwrócić false
ekkis
0
Jeśli musisz częściej porównywać łańcuch źródłowy z innymi łańcuchami, eleganckim rozwiązaniem jest użycie wyrażenia regularnego.
std::wstring first = L"Test";
std::wstring second = L"TEST";
std::wregex pattern(first, std::wregex::icase);bool isEqual = std::regex_match(second, pattern);
Próbowałem tego, ale błąd kompilacji: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing
kiepski pomysł. To najgorsze rozwiązanie.
Behrouz.M
To nie jest dobre rozwiązanie, ale nawet jeśli chcesz go użyć, potrzebujesz litery L przed swoimi najszerszymi stałymi, np. L „TEST”
celticminstrel
Byłoby miło, gdyby ktoś mógł wyjaśnić, dlaczego jest to najgorsze rozwiązanie. Z powodu problemów z wydajnością? Tworzenie wyrażenia regularnego jest kosztowne, ale potem porównanie powinno być naprawdę szybkie.
smibe
jest użyteczny i przenośny, głównym problemem jest to, że po pierwsze nie może zawierać żadnych znaków, których używa regex. Z tego powodu nie można go używać jako ogólnego porównania ciągów. Będzie również wolniejszy, jest flaga, która sprawia, że działa tak, jak mówi Smibe, ale nadal nie może być używana jako funkcja ogólna.
Ben
0
Prostym sposobem na porównanie dwóch ciągów znaków w c ++ (przetestowanych pod Windows) jest użycie _stricmp
// Case insensitive (could use equivalent _stricmp)
result = _stricmp( string1, string2 );
Jeśli chcesz używać ze std :: string, przykład:
std::string s1 = string("Hello");if( _stricmp(s1.c_str(),"HELLO")==0)
std::cout <<"The string are equals.";
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;}}}
można by to prawdopodobnie uczynić znacznie bardziej wydajnym, ale tutaj jest nieporęczna wersja z wszystkimi odsłoniętymi fragmentami.
nie wszystko jest przenośne, ale działa dobrze z tym, co jest na moim komputerze (nie mam pojęcia, jestem obrazami, a nie słowami)
To nie obsługuje zestawów znaków innych niż angielski.
Robert Andrzejuk
-3
Prostym sposobem na porównanie ciągów znaków, które różnią się jedynie małymi i wielkimi literami, jest porównanie ascii. Wszystkie wielkie i małe litery różnią się o 32 bity w tabeli ascii, korzystając z tych informacji, mamy następujące ...
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
. W przeciwnym razie przeczytaj, co ma do powiedzenia Herb .strcasecmp
nie jest częścią standardu i brakuje go w co najmniej jednym wspólnym kompilatorze.Odpowiedzi:
Boost zawiera przydatny algorytm do tego:
źródło
Skorzystaj ze standardu
char_traits
. Przypomnijmy, żestd::string
w rzeczywistości jest typedef dlastd::basic_string<char>
lub bardziej jawniestd::basic_string<char, std::char_traits<char> >
. Tenchar_traits
typ opisuje, w jaki sposób znaki się porównują, jak kopiują, jak rzutują itp. Wystarczy, że napiszesz nowy ciąg znakówbasic_string
i nadasz mu własny zwyczaj,char_traits
który porównuje wielkość liter bez rozróżnienia.Szczegóły znajdują się na Guru tygodnia nr 29 .
źródło
typedef std::basic_string<char, ci_char_traits<char> > istring
nietypedef std::basic_string<char, std::char_traits<char> > string
.Problem z doładowaniem polega na tym, że musisz się połączyć i polegać na doładowaniu. W niektórych przypadkach nie jest to łatwe (np. Android).
A używanie char_traits oznacza wszystko porównania nie uwzględniają wielkości liter, co zwykle nie jest tym, czego chcesz.
To powinno wystarczyć. Powinien być dość wydajny. Nie obsługuje jednak Unicode ani nic takiego.
Aktualizacja: Bonusowa wersja C ++ 14 (
#include <algorithm>
):źródło
Jeśli korzystasz z systemu POSIX, możesz użyć strcasecmp . Ta funkcja nie jest jednak częścią standardowego C i nie jest dostępna w systemie Windows. Spowoduje to porównanie bez rozróżniania wielkości liter na 8-bitowych znakach, o ile ustawieniem narodowym jest POSIX. Jeśli ustawieniami narodowymi nie jest POSIX, wyniki są niezdefiniowane (więc może wykonać zlokalizowane porównanie lub nie). Odpowiednik szerokich znaków nie jest dostępny.
W przeciwnym razie duża liczba historycznych implementacji biblioteki C ma funkcje stricmp () i strnicmp (). Visual C ++ w systemie Windows przemianował je wszystkie, poprzedzając je znakiem podkreślenia, ponieważ nie są one częścią standardu ANSI, więc w tym systemie nazywane są _stricmp lub _strnicmp . Niektóre biblioteki mogą mieć także funkcje równoważne szerokim znakom lub wielobajtom (zwykle nazywane np. Wcsicmp, mbcsicmp i tak dalej).
Zarówno C, jak i C ++ są w dużej mierze nieświadomi problemów związanych z internacjonalizacją, więc nie ma dobrego rozwiązania tego problemu, z wyjątkiem korzystania z biblioteki innej firmy. Sprawdź IBM ICU (International Components for Unicode), jeśli potrzebujesz solidnej biblioteki dla C / C ++. ICU jest przeznaczony zarówno dla systemów Windows, jak i Unix.
źródło
Czy mówisz o głupim porównaniu bez rozróżniania wielkości liter lub o pełnym znormalizowanym porównaniu Unicode?
Głupie porównanie nie znajdzie ciągów, które mogą być takie same, ale nie są binarne.
Przykład:
Wszystkie są równoważne, ale mają również różne reprezentacje binarne.
To powiedziawszy, Normalizacja Unicode powinna być obowiązkową lekturą, szczególnie jeśli planujesz wspierać Hangul, Thai i inne języki azjatyckie.
Ponadto IBM opatentował najbardziej zoptymalizowane algorytmy Unicode i udostępnił je publicznie. Utrzymują także implementację: IBM ICU
źródło
boost :: iequals nie jest kompatybilny z utf-8 w przypadku napisów. Możesz użyć boost :: locale .
źródło
Moją pierwszą myślą o wersji innej niż Unicode było zrobienie czegoś takiego:
źródło
Możesz używać w systemie
strcasecmp
Unix lubstricmp
Windows.Jedną z rzeczy, o których nie wspomniano do tej pory, jest to, że jeśli używasz ciągów stl z tymi metodami, warto najpierw porównać długość tych dwóch ciągów, ponieważ te informacje są już dostępne w klasie ciągów. Może to uniemożliwić wykonanie kosztownego porównania ciągów, jeśli dwa porównywane ciągi nie będą w ogóle nawet tej samej długości.
źródło
Funkcje ciągów Visual C ++ obsługujące Unicode: http://msdn.microsoft.com/en-us/library/cc194799.aspx
tym, którego prawdopodobnie szukasz
_wcsnicmp
źródło
Próbuję zebrać dobrą odpowiedź ze wszystkich postów, więc pomóż mi edytować to:
Oto metoda na zrobienie tego, chociaż transformuje ciągi i nie jest przyjazna dla Unicode, powinna być przenośna, co jest plusem:
Z tego, co przeczytałem, jest on bardziej przenośny niż stricmp (), ponieważ stricmp () nie jest tak naprawdę częścią biblioteki std, ale jest implementowany tylko przez większość dostawców kompilatorów.
Aby uzyskać naprawdę przyjazną dla Unicode implementację, musisz wyjść poza bibliotekę std. Jedną dobrą biblioteką innej firmy jest IBM ICU (International Components for Unicode)
Również boost :: iequals zapewnia dość dobrą użyteczność do wykonywania tego rodzaju porównań.
źródło
transform
cały ciąg przed porównaniemMożesz użyć powyższego kodu w C ++ 14, jeśli nie masz możliwości użycia boost. Musisz używać
std::towlower
do szerokich znaków.źródło
str1.size() == str2.size() &&
z przodu, aby nie wykraczało poza granice, gdy str2 jest prefiksem str1.Boost.String Biblioteka posiada wiele algorytmów robi case-insenstive porównań i tak dalej.
Możesz wdrożyć własne, ale po co męczyć się, gdy już zostało to zrobione?
źródło
FYI
strcmp()
istricmp()
są podatne na przepełnienie bufora, ponieważ przetwarzają tylko, dopóki nie osiągną zerowego terminatora. Jest bezpieczniejszy w użyciu_strncmp()
i_strnicmp()
.źródło
stricmp()
istrnicmp()
nie są częścią standardu POSIX :-( Jednak można znaleźćstrcasecmp()
,strcasecmp_l()
,strncasecmp()
istrncasecmp_l()
POSIX nagłówkustrings.h
:-) zobaczyć opengroup.orgZobacz
std::lexicographical_compare
:Próbny
źródło
std::tolower
działa tylko wtedy, gdy znak jest zakodowany w ASCII. Nie ma takiej gwarancji nastd::string
- więc może być łatwo niezdefiniowanym zachowaniem.Ze względu na moje podstawowe potrzeby porównywania ciągów bez rozróżniania wielkości liter wolę nie używać biblioteki zewnętrznej, ani też nie chcę osobnej klasy ciągów z cechami bez rozróżniania wielkości liter, która jest niezgodna ze wszystkimi innymi ciągami.
Więc wymyśliłem to:
Prosta funkcja z jednym przeciążeniem dla char i innym dla whar_t. Nie używa niczego niestandardowego, więc powinno być dobrze na każdej platformie.
Porównanie równości nie bierze pod uwagę takich kwestii, jak kodowanie o zmiennej długości i normalizacja Unicode, ale basic_string nie obsługuje tego, o czym jestem świadomy, i zwykle nie jest to problem.
W przypadkach, w których wymagana jest bardziej wyrafinowana leksykograficzna manipulacja tekstem, wystarczy użyć biblioteki innej firmy, takiej jak Boost, czego należy się spodziewać.
źródło
Krótko i miło. Żadnych innych zależności, oprócz rozszerzonej biblioteki std C.
zwraca true, jeśli
str1
istr2
są równe.strcasecmp
nie może istnieć, nie może być analogistricmp
,strcmpi
itpPrzykładowy kod:
Wynik:
źródło
stricmp
,strcmpi
,strcasecmp
, Itd. Dziękuję. edytowana wiadomość.cout << boolalpha
zamiast mojego,bool2str
ponieważ domyślnie przekształca bool w znaki dla strumienia.Wykonanie tego bez użycia wzmocnienia można wykonać, uzyskując wskaźnik łańcucha C za
c_str()
pomocąstrcasecmp
:źródło
Zakładając, że szukasz metody, a nie magicznej funkcji, która już istnieje, szczerze mówiąc, nie ma lepszego sposobu. Wszyscy moglibyśmy pisać fragmenty kodu za pomocą sprytnych sztuczek dla ograniczonych zestawów znaków, ale pod koniec dnia w którymś momencie musisz przekonwertować znaki.
Najlepszym podejściem do tej konwersji jest zrobienie tego przed porównaniem. Zapewnia to dużą elastyczność, jeśli chodzi o schematy kodowania, których faktyczny operator porównania powinien być nieświadomy.
Możesz oczywiście „ukryć” tę konwersję za własną funkcją lub klasą łańcuchową, ale przed porównaniem wciąż musisz przekonwertować łańcuchy.
źródło
Napisałem rozróżniającą wielkość liter wersję char_traits do użycia ze std :: basic_string w celu wygenerowania std :: string, który nie rozróżnia wielkości liter podczas wykonywania porównań, wyszukiwania itp. Za pomocą wbudowanych funkcji członkowskich std :: basic_string.
Innymi słowy, chciałem zrobić coś takiego.
... z którymi std :: string nie może sobie poradzić. Oto użycie moich nowych char_traits:
... a oto implementacja:
źródło
Mam duże doświadczenie w korzystaniu z bibliotek International Components for Unicode - są one niezwykle wydajne i zapewniają metody konwersji, obsługę ustawień regionalnych, renderowanie daty i godziny, mapowanie wielkości liter (których nie chcesz) oraz sortowanie , który obejmuje porównanie bez rozróżniania wielkości liter i akcentów (i więcej). Użyłem tylko bibliotek C ++, ale wydaje się, że mają również wersję Java.
Istnieją metody przeprowadzania znormalizowanych porównań, o których mowa w @Coincoin, i mogą nawet uwzględniać ustawienia regionalne - na przykład (i ten przykład sortowania, nie ściśle równości), tradycyjnie w języku hiszpańskim (w Hiszpanii), kombinacja liter „ll” sortuje między „l” i „m”, więc „lz” <„ll” <„ma”.
źródło
Wystarczy użyć do rozróżniania wielkości liter
strcmp()
i /strcmpi()
lub bezstricmp()
rozróżniania wielkości liter. Które są w pliku nagłówkowym<string.h>
format:
Stosowanie:
Wynik
Apple i ApPlE są takie same
a jest przed b, więc jabłko jest przed piłką
źródło
Późno na imprezę, ale tutaj jest wariant, który wykorzystuje
std::locale
, a zatem poprawnie obsługuje turecki:daje funktor, który wykorzystuje aktywne ustawienia regionalne do konwersji znaków na małe litery, których można następnie użyć
std::transform
do wygenerowania ciągów małych liter:Działa to również w przypadku
wchar_t
ciągów opartych.źródło
Tylko uwaga na temat jakiejkolwiek metody, którą ostatecznie wybierzesz, jeśli ta metoda obejmuje użycie
strcmp
, niektóre odpowiedzi sugerują:strcmp
ogólnie nie działa z danymi Unicode. Ogólnie rzecz biorąc, nie działa nawet z kodowaniem Unicode opartym na bajtach, takim jak utf-8, ponieważstrcmp
tylko porównania bajt na bajt i punkty kodu Unicode zakodowane w utf-8 mogą zająć więcej niż 1 bajt. Jedynym konkretnym przypadkiemstrcmp
poprawnie obsługującym przypadek Unicode jest sytuacja, gdy łańcuch zakodowany za pomocą kodowania bajtowego zawiera tylko punkty kodowe poniżej U + 00FF - wtedy wystarczy porównanie bajtów na bajt.źródło
Na początku 2013 r. Projekt ICU, prowadzony przez IBM, jest dość dobrą odpowiedzią na to.
http://site.icu-project.org/
ICU to „kompletna, przenośna biblioteka Unicode, która ściśle śledzi standardy branżowe”. W przypadku konkretnego problemu porównywania ciągów obiekt Collation robi to, co chcesz.
Projekt Mozilla przyjął ICU do internacjonalizacji w Firefoksie w połowie 2012 roku; możesz śledzić dyskusję inżynierską, w tym kwestie dotyczące systemów kompilacji i rozmiaru pliku danych, tutaj:
źródło
Wygląda na to, że powyższe rozwiązania nie używają metody porównywania i nie wdrażają ponownie sumy, więc oto moje rozwiązanie i mam nadzieję, że zadziała dla ciebie (działa dobrze).
źródło
Jeśli nie chcesz używać biblioteki Boost, oto rozwiązanie, używając tylko standardowego nagłówka io C ++.
źródło
Jeśli musisz częściej porównywać łańcuch źródłowy z innymi łańcuchami, eleganckim rozwiązaniem jest użycie wyrażenia regularnego.
źródło
error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Prostym sposobem na porównanie dwóch ciągów znaków w c ++ (przetestowanych pod Windows) jest użycie _stricmp
Jeśli chcesz używać ze std :: string, przykład:
Aby uzyskać więcej informacji tutaj: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx
źródło
można by to prawdopodobnie uczynić znacznie bardziej wydajnym, ale tutaj jest nieporęczna wersja z wszystkimi odsłoniętymi fragmentami.
nie wszystko jest przenośne, ale działa dobrze z tym, co jest na moim komputerze (nie mam pojęcia, jestem obrazami, a nie słowami)
źródło
Prostym sposobem na porównanie ciągów znaków, które różnią się jedynie małymi i wielkimi literami, jest porównanie ascii. Wszystkie wielkie i małe litery różnią się o 32 bity w tabeli ascii, korzystając z tych informacji, mamy następujące ...
źródło