Perbandingan string case-insensitive dalam C ++ [ditutup]
373
Apa cara terbaik untuk melakukan perbandingan string case-insensitive dalam C ++ tanpa mengubah string menjadi semua huruf besar atau semua huruf kecil?
Harap tunjukkan apakah metode ini ramah Unicode dan seberapa portabelnya.
@ [Adam] (# 11679): Meskipun varian ini bagus dalam hal kegunaan, buruk dalam hal kinerja karena membuat salinan yang tidak perlu. Saya mungkin mengabaikan sesuatu tetapi saya percaya cara terbaik (non-Unicode) adalah menggunakan std::stricmp. Jika tidak, membaca apa Herb katakan .
Konrad Rudolph
Dalam c, seseorang biasanya dipaksa untuk mengungguli seluruh string kemudian membandingkan dengan cara itu - atau roll membandingkan Anda sendiri: P
Michael Dorgan
pertanyaan selanjutnya memiliki jawaban yang lebih sederhana: strcasecmp (setidaknya untuk kompiler BSD & POSIX) stackoverflow.com/questions/9182912/…
Móż
@ Mσᶎ pertanyaan ini juga memiliki jawaban itu, dengan peringatan penting yang strcasecmpbukan bagian dari standar dan hilang dari setidaknya satu kompiler umum.
Mark Ransom
Jawaban:
318
Boost menyertakan algoritme yang berguna untuk ini:
#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}
Tidak, karena UTF-8 memungkinkan string identik dikodekan dengan kode biner yang berbeda, karena aksen, gabungan, masalah bidi, dll.
vy32
10
@ vy32 Itu benar-benar salah! Kombinasi UTF-8 saling eksklusif. Itu harus selalu menggunakan representasi sesingkat mungkin, jika tidak, itu urutan UTF-8 yang salah atau titik kode yang harus diperlakukan dengan hati-hati.
Wiz
48
@ Wiz, Anda mengabaikan masalah normalisasi string Unicode. ñ dapat direpresentasikan sebagai gabungan ˜ diikuti oleh n, atau dengan karakter ñ. Anda perlu menggunakan normalisasi string Unicode sebelum melakukan pembandingan. Harap tinjau Unicode Laporan Teknis # 15, unicode.org/reports/tr15
Manfaatkan standar ini char_traits. Ingatlah bahwa std::stringsebenarnya adalah typedef untuk std::basic_string<char>, atau lebih eksplisit std::basic_string<char, std::char_traits<char> >,. The char_traitsTipe menjelaskan bagaimana karakter membandingkan, bagaimana mereka menyalin, bagaimana mereka melemparkan dll Semua perlu Anda lakukan adalah typedef string baru lebih basic_string, dan memberikan dengan kustom Anda sendiri char_traitsyang membandingkan kasus insensitively.
Sejauh yang saya tahu dari eksperimen saya sendiri, ini membuat tipe string baru Anda tidak kompatibel dengan std :: string.
Zan Lynx
8
Tentu saja - untuk kebaikannya sendiri. String case-insensitive adalah sesuatu yang lain:, typedef std::basic_string<char, ci_char_traits<char> > istringtidak typedef std::basic_string<char, std::char_traits<char> > string.
Andreas Spindler
232
"Yang perlu Anda lakukan ..."
Tim MB
3
@Nathan mungkin menggunakan kompiler yang mampu melakukan CSE dasar pada kode ...
The Paramagnetic Croissant
17
Setiap konstruksi bahasa yang memaksa kegilaan semacam itu dalam kasus sepele ini harus dan dapat ditinggalkan tanpa penyesalan.
Erik Aronesty
86
Masalahnya dengan peningkatan adalah Anda harus terhubung dengan dan bergantung pada dorongan. Tidak mudah dalam beberapa kasus (mis. Android).
Dan menggunakan char_traits berarti semua perbandingan Anda tidak peka terhadap huruf besar-kecil, yang biasanya tidak seperti yang Anda inginkan.
Ini sudah cukup. Itu harus cukup efisien. Tidak menangani unicode atau apapun.
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;}
Pembaruan: Versi Bonus C ++ 14 ( #include <algorithm>):
Sebenarnya, pustaka string boost adalah pustaka header saja, jadi tidak perlu menautkan apa pun. Selain itu, Anda dapat menggunakan utilitas 'bcp' boost untuk menyalin hanya header string ke hierarki sumber Anda, jadi Anda tidak perlu memerlukan pustaka boost penuh.
Gretchen
Ah saya tidak tahu tentang bcp, itu terlihat sangat berguna. Terimakasih atas infonya!
Timmmm
9
Baik untuk mengetahui versi sederhana dan tidak-meningkatkan-ketergantungan.
Deqing
2
@Anna Text Library dari boost perlu dibangun dan ditautkan. Itu menggunakan IBM ICU.
Behrouz.M
Juga tersedia dengan C ++ 11
martian
58
Jika Anda menggunakan sistem POSIX, Anda dapat menggunakan strcasecmp . Namun, fungsi ini bukan bagian dari standar C, juga tidak tersedia di Windows. Ini akan melakukan perbandingan case-insensitive pada karakter 8-bit, selama lokalnya adalah POSIX. Jika lokal bukan POSIX, hasilnya tidak terdefinisi (sehingga mungkin melakukan perbandingan lokal, atau mungkin tidak). Setara karakter lebar tidak tersedia.
Kegagalan itu, sejumlah besar implementasi C library bersejarah memiliki fungsi stricmp () dan strnicmp (). Visual C ++ pada Windows mengganti nama semua ini dengan mengawali mereka dengan garis bawah karena mereka bukan bagian dari standar ANSI, jadi pada sistem itu mereka disebut _stricmp atau _strnicmp . Beberapa perpustakaan mungkin juga memiliki fungsi setara karakter lebar atau multibyte (biasanya dinamakan misalnya wcsicmp, mbcsicmp, dan sebagainya).
C dan C ++ sama-sama tidak mengetahui masalah internasionalisasi, jadi tidak ada solusi yang baik untuk masalah ini, kecuali menggunakan perpustakaan pihak ketiga. Periksa IBM ICU (Komponen Internasional untuk Unicode) jika Anda memerlukan pustaka yang kuat untuk C / C ++. ICU adalah untuk sistem Windows dan Unix.
Anda dapat menggunakan strcasecmpdi Unix, atau stricmpdi Windows.
Satu hal yang belum disebutkan sejauh ini adalah bahwa jika Anda menggunakan string stl dengan metode ini, ada baiknya untuk terlebih dahulu membandingkan panjang kedua string, karena informasi ini sudah tersedia untuk Anda di kelas string. Ini bisa mencegah melakukan perbandingan string yang mahal jika dua string yang Anda bandingkan bahkan tidak sama panjangnya.
Karena menentukan panjang string terdiri dari iterasi setiap karakter dalam string dan membandingkannya dengan 0, apakah benar-benar ada banyak perbedaan antara itu dan hanya membandingkan string segera? Saya kira Anda mendapatkan memori lokalitas yang lebih baik dalam kasus di mana kedua string tidak cocok, tetapi mungkin hampir 2x runtime dalam kasus pertandingan.
Itu fakta kecil yang menyenangkan, tetapi tidak banyak berpengaruh di sini. strcasecmp () dan stricmp () keduanya menggunakan string C yang tidak didekorasi, sehingga tidak ada string std :: string yang terlibat.
uliwitness
3
Metode ini akan mengembalikan -1 jika Anda membandingkan "a" vs "ab". Panjangnya berbeda tetapi "a" muncul sebelum "ab". Jadi, hanya membandingkan panjang tidak layak jika penelepon peduli tentang pemesanan.
Dari apa yang saya baca ini lebih portabel daripada stricmp () karena stricmp () sebenarnya bukan bagian dari perpustakaan std, tetapi hanya diimplementasikan oleh sebagian besar vendor kompiler.
Untuk mendapatkan implementasi yang benar-benar ramah Unicode tampaknya Anda harus pergi ke luar perpustakaan std. Satu perpustakaan pihak ketiga yang bagus adalah IBM ICU (Komponen Internasional untuk Unicode)
Juga meningkatkan :: iequals menyediakan utilitas yang cukup baik untuk melakukan perbandingan semacam ini.
dapatkah Anda memberi tahu, apa artinya :: tolower, mengapa Anda bisa menggunakan tolower alih-alih tolower (), dan apa itu '::' sebelumnya? terima kasih
VextoR
17
Ini bukan solusi yang sangat efisien - Anda membuat salinan dari kedua string dan mengubah semuanya bahkan jika karakter pertama berbeda.
Timmmm
2
Jika Anda akan tetap membuat salinan, mengapa tidak memberikan nilai alih-alih dengan referensi?
celticminstrel
Saya pikir ini tip sederhana tanpa dorongan. :)
cmcromance
1
pertanyaannya diajukan secara eksplisit untuk tidak transformseluruh string sebelum perbandingan
Anda dapat menggunakan kode di atas dalam C ++ 14 jika Anda tidak berada dalam posisi untuk menggunakan boost. Anda harus menggunakan std::towloweruntuk karakter lebar.
"... kenapa repot-repot kalau sudah dilakukan?" - bagaimana jika Anda tidak menggunakan Peningkatan? OP tidak memiliki tag dengan pertanyaan.
jww
11
FYI, strcmp()dan stricmp()rentan terhadap buffer overflow, karena mereka hanya memproses sampai mereka mencapai terminator nol. Lebih aman digunakan _strncmp()dan _strnicmp().
Benar, meskipun overREADing buffer secara signifikan lebih berbahaya daripada overWRITEing buffer.
Adam Rosenfield
4
stricmp()dan strnicmp()bukan bagian dari standar POSIX :-( Namun Anda dapat menemukan strcasecmp(), strcasecmp_l(), strncasecmp()dan strncasecmp_l()di POSIX sundulan strings.h:-) melihat opengroup.org
olibre
2
@AdamRosenfield 'lebih buruk' tergantung pada konteks. Dalam keamanan, kadang-kadang inti dari overwrite adalah untuk mendapatkan overread.
Metode ini berpotensi tidak aman dan tidak portabel. std::tolowerberfungsi hanya jika karakternya dikodekan ASCII. Tidak ada jaminan seperti itu untuk std::string- sehingga perilaku itu tidak dapat didefinisikan dengan mudah.
plasmacel
@plasmacel Kemudian gunakan fungsi yang bekerja dengan penyandian lainnya.
Brian Rodriguez
9
Untuk kebutuhan perbandingan string case sensitif dasar saya, saya lebih suka tidak harus menggunakan perpustakaan eksternal, saya juga tidak ingin kelas string terpisah dengan sifat-sifat case sensitif yang tidak kompatibel dengan semua string saya yang lain.
Fungsi sederhana dengan satu overload untuk char dan lainnya untuk whar_t. Tidak menggunakan apa pun yang tidak standar sehingga harus baik-baik saja pada platform apa pun.
Perbandingan kesetaraan tidak akan mempertimbangkan masalah seperti pengodean panjang variabel dan normalisasi Unicode, tetapi basic_string tidak memiliki dukungan untuk itu yang saya sadari dan itu biasanya bukan masalah.
Dalam kasus di mana manipulasi leksikografis yang lebih canggih dari teks diperlukan, maka Anda hanya harus menggunakan perpustakaan pihak ketiga seperti Boost, yang diharapkan.
Anda mungkin bisa membuat satu fungsi itu jika Anda membuatnya menjadi templat dan menggunakan basic_string <T> alih-alih versi string / wstring yang terpisah?
uliwitness
2
Bagaimana templat fungsi tunggal memohon baik toupper atau towupper tanpa menggunakan spesialisasi atau makro, fungsi yang berlebihan tampak seperti implementasi yang lebih sederhana dan lebih tepat daripada keduanya.
Neutrino
9
Pendek dan bagus. Tidak ada dependensi lain, selain std C lib diperpanjang .
strcasecmp(str1.c_str(), str2.c_str())==0
mengembalikan true jika str1dan str2sama.
strcasecmpmungkin tidak ada, mungkin ada analog stricmp, strcmpi, dll
Kode contoh:
#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;}
Dengan asumsi Anda sedang mencari metode dan bukan fungsi sihir yang sudah ada, terus terang tidak ada cara yang lebih baik. Kita semua dapat menulis cuplikan kode dengan trik pintar untuk rangkaian karakter terbatas, tetapi pada akhirnya di suatu tempat Anda harus mengonversi karakter.
Pendekatan terbaik untuk konversi ini adalah melakukannya sebelum perbandingan. Ini memungkinkan Anda banyak fleksibilitas dalam hal skema penyandian, yang seharusnya tidak diperhatikan oleh operator perbandingan Anda.
Tentu saja Anda dapat 'menyembunyikan' konversi ini di belakang fungsi atau kelas string Anda sendiri, tetapi Anda masih perlu mengonversi string sebelum perbandingan.
Saya menulis versi char_traits case-insensitive untuk digunakan dengan std :: basic_string untuk menghasilkan string std :: yang tidak peka huruf besar-kecil ketika melakukan perbandingan, pencarian, dll menggunakan fungsi anggota std :: basic_string bawaan.
Jadi dengan kata lain, saya ingin melakukan sesuatu seperti ini.
std::string a ="Hello, World!";
std::string b ="hello, world!";
assert( a == b );
... yang std :: string tidak dapat menangani. Inilah penggunaan char_traits baru saya:
std::istring a ="Hello, World!";
std::istring b ="hello, world!";
assert( a == b );
... dan inilah implementasinya:
/* ---
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;
Ini berfungsi untuk karakter reguler, tetapi tidak akan berfungsi untuk semua Unicode, karena kapitalisasi tidak harus dua arah (ada contoh yang baik dalam bahasa Yunani yang melibatkan sigma yang tidak dapat saya ingat sekarang; sesuatu seperti itu memiliki dua huruf kecil dan huruf besar satu , dan Anda tidak bisa mendapatkan perbandingan yang tepat)
coppro
1
Itu benar-benar cara yang salah untuk melakukannya. Sensitivitas huruf tidak boleh menjadi properti dari string itu sendiri. Apa yang terjadi ketika objek string yang sama membutuhkan perbandingan case-sensitive dan case-sensitive?
Ferruccio
Jika sensitivitas huruf tidak sesuai untuk menjadi "bagian dari" string, maka fungsi find () sama sekali tidak. Yang mana, bagi Anda, mungkin benar, dan itu tidak masalah. IMO hal terbesar tentang C ++ adalah ia tidak memaksakan paradigma tertentu pada programmer. Ini adalah apa yang Anda inginkan / inginkan.
John Dibling
Sebenarnya, saya pikir sebagian besar C + + - guru (seperti yang ada di komite standar) setuju bahwa itu adalah kesalahan untuk menempatkan find () di std :: basic_string <> bersama dengan banyak hal lain yang bisa ditempatkan di fungsi gratis. Selain itu ada beberapa masalah dengan memasukkannya ke dalam tipe.
Andreas Magnusson
Seperti yang telah ditunjukkan orang lain, ada dua hal utama yang salah dengan solusi ini (ironisnya, satu adalah antarmuka dan yang lainnya adalah implementasinya ;-)).
Konrad Rudolph
4
Saya memiliki pengalaman yang baik dalam menggunakan Komponen Internasional untuk pustaka Unicode - mereka sangat kuat, dan menyediakan metode untuk konversi, dukungan lokal, rendering tanggal dan waktu, pemetaan kasus (yang sepertinya tidak Anda inginkan), dan pengumpulan , yang mencakup perbandingan case-and-accentitive (dan banyak lagi). Saya hanya menggunakan versi C ++ dari pustaka, tetapi mereka tampaknya memiliki versi Java juga.
Ada metode untuk melakukan pembandingan yang dinormalisasi sebagaimana dimaksud oleh @Coincoin, dan bahkan dapat menjelaskan lokal - misalnya (dan ini contoh penyortiran, tidak sepenuhnya kesetaraan), secara tradisional dalam bahasa Spanyol (di Spanyol), kombinasi huruf "ll" akan memilah antara "l" dan "m", jadi "lz" <"ll" <"ma".
Cukup gunakan strcmp()untuk case sensitive dan strcmpi()atau stricmp()untuk case sensitive case. Yang keduanya di file header<string.h>
format:
int strcmp(constchar*,constchar*);//for case sensitiveint strcmpi(constchar*,constchar*);//for case insensitive
Pemakaian:
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;
Mengundurkan diri karena ini bukan cara C ++ dalam melakukan sesuatu.
Thomas Daugaard
Ini adalah konvensi c ++ di universitas saya tetapi saya akan mengingatnya saat memposting di sini
reubenjohn
4
stricmp adalah ekstensi Microsoft AFAIK. BSD tampaknya memiliki strcasecmp () sebagai gantinya.
uliwitness
3
Terlambat ke pesta, tetapi di sini ada varian yang menggunakan std::locale, dan dengan demikian menangani Turki dengan benar:
auto tolower = std::bind1st(
std::mem_fun(&std::ctype<char>::tolower),&std::use_facet<std::ctype<char>>(
std::locale()));
memberi Anda functor yang menggunakan lokal aktif untuk mengonversi karakter menjadi huruf kecil, yang kemudian dapat Anda gunakan std::transformuntuk menghasilkan string huruf kecil:
std::string left ="fOo";
transform(left.begin(), left.end(), left.begin(), tolower);
Hanya catatan tentang metode apa pun yang akhirnya Anda pilih, jika metode itu terjadi termasuk penggunaan strcmp yang beberapa jawaban sarankan:
strcmptidak bekerja dengan data Unicode secara umum. Secara umum, itu bahkan tidak bekerja dengan encode Unicode berbasis byte, seperti utf-8strcmp hanya membuat perbandingan byte per byte dan titik kode Unicode yang dikodekan dalam utf-8 dapat membutuhkan lebih dari 1 byte. Satu-satunya kasus Unicode khusus yang strcmpditangani dengan benar adalah ketika string yang dikodekan dengan pengkodean berbasis byte hanya berisi poin kode di bawah U + 00FF - maka perbandingan byte-per-byte sudah cukup.
ICU adalah "perpustakaan Unicode portabel yang lengkap yang secara ketat melacak standar industri." Untuk masalah spesifik perbandingan string, objek Collation melakukan apa yang Anda inginkan.
Proyek Mozilla mengadopsi ICU untuk internasionalisasi di Firefox pada pertengahan 2012; Anda dapat melacak diskusi teknik, termasuk masalah sistem pembangunan dan ukuran file data, di sini:
Sepertinya solusi di atas tidak menggunakan metode bandingkan dan menerapkan total lagi jadi di sini adalah solusi saya dan berharap itu berfungsi untuk Anda (Ini berfungsi dengan baik).
Jika Anda tidak ingin menggunakan perpustakaan Boost maka di sini ada solusi untuk itu hanya menggunakan header C ++ io standar.
#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;}
Saya percaya std :: toupper ada di #include <cctype>, Anda mungkin perlu memasukkannya.
David Ledger
Jika Anda akan menggunakan versi global seperti ini :: toupper maka Anda mungkin tidak perlu memasukkan <ctype> karena ada dua versi versi c dan versi c ++ dengan lokal kurasa. Jadi lebih baik menggunakan versi global ":: toupper ()"
HaSeeB MiR
solusi ini gagal ketika salah satu string kosong: "" - itu mengembalikan true dalam kasus ketika itu harus mengembalikan false
ekkis
0
Jika Anda harus membandingkan string sumber lebih sering dengan string lain, salah satu solusi elegan adalah menggunakan regex.
std::wstring first = L"Test";
std::wstring second = L"TEST";
std::wregex pattern(first, std::wregex::icase);bool isEqual = std::regex_match(second, pattern);
Mencoba ini tetapi kompilasi kesalahan: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing
ide buruk. Itu solusi terburuk.
Behrouz.M
Ini bukan solusi yang baik, tetapi bahkan jika Anda ingin menggunakannya, Anda memerlukan L di depan konstanta widestring Anda, misalnya L "TEST"
celticminstrel
Akan lebih baik jika seseorang bisa menjelaskan mengapa itu adalah solusi terburuk. Karena masalah kinerja? Membuat regex itu mahal, tetapi setelah itu perbandingannya harus sangat cepat.
smibe
itu bisa digunakan dan portabel, masalah utama adalah yang pertama tidak dapat berisi karakter yang digunakan regex. Itu tidak dapat digunakan sebagai perbandingan string umum karena itu. Ini juga akan lebih lambat, ada bendera untuk membuatnya berfungsi seperti yang dikatakan smibe tetapi masih tidak dapat digunakan sebagai fungsi umum.
Ben
0
Cara sederhana untuk membandingkan dua string dalam c ++ (diuji untuk windows) adalah menggunakan _stricmp
// Case insensitive (could use equivalent _stricmp)
result = _stricmp( string1, string2 );
Jika Anda ingin menggunakan dengan std :: string, contoh:
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;}}}
ini mungkin bisa dibuat jauh lebih efisien, tetapi di sini ada versi besar dengan semua bitnya telanjang.
tidak semua yang portabel, tetapi bekerja dengan baik dengan apa pun yang ada di komputer saya (tidak tahu, saya gambar bukan kata-kata)
Ini bukan dukungan Unicode yang merupakan pertanyaan yang diajukan.
Behrouz.M
Ini tidak mendukung rangkaian karakter non-Inggris.
Robert Andrzantai
-3
Cara mudah untuk membandingkan string yang hanya berbeda dengan huruf kecil dan huruf besar adalah dengan melakukan perbandingan ascii. Semua huruf besar dan kecil berbeda 32 bit dalam tabel ascii, menggunakan informasi ini kami memiliki ...
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}}
Menurut ini, "++ j" akan ditemukan sama dengan "KKJ", dan "1234" akan ditemukan sama dengan "QRST". Saya ragu itu adalah sesuatu yang diinginkan siapa pun.
std::stricmp
. Jika tidak, membaca apa Herb katakan .strcasecmp
bukan bagian dari standar dan hilang dari setidaknya satu kompiler umum.Jawaban:
Boost menyertakan algoritme yang berguna untuk ini:
sumber
Manfaatkan standar ini
char_traits
. Ingatlah bahwastd::string
sebenarnya adalah typedef untukstd::basic_string<char>
, atau lebih eksplisitstd::basic_string<char, std::char_traits<char> >
,. Thechar_traits
Tipe menjelaskan bagaimana karakter membandingkan, bagaimana mereka menyalin, bagaimana mereka melemparkan dll Semua perlu Anda lakukan adalah typedef string baru lebihbasic_string
, dan memberikan dengan kustom Anda sendirichar_traits
yang membandingkan kasus insensitively.Rinciannya ada di Guru of The Week nomor 29 .
sumber
typedef std::basic_string<char, ci_char_traits<char> > istring
tidaktypedef std::basic_string<char, std::char_traits<char> > string
.Masalahnya dengan peningkatan adalah Anda harus terhubung dengan dan bergantung pada dorongan. Tidak mudah dalam beberapa kasus (mis. Android).
Dan menggunakan char_traits berarti semua perbandingan Anda tidak peka terhadap huruf besar-kecil, yang biasanya tidak seperti yang Anda inginkan.
Ini sudah cukup. Itu harus cukup efisien. Tidak menangani unicode atau apapun.
Pembaruan: Versi Bonus C ++ 14 (
#include <algorithm>
):sumber
Jika Anda menggunakan sistem POSIX, Anda dapat menggunakan strcasecmp . Namun, fungsi ini bukan bagian dari standar C, juga tidak tersedia di Windows. Ini akan melakukan perbandingan case-insensitive pada karakter 8-bit, selama lokalnya adalah POSIX. Jika lokal bukan POSIX, hasilnya tidak terdefinisi (sehingga mungkin melakukan perbandingan lokal, atau mungkin tidak). Setara karakter lebar tidak tersedia.
Kegagalan itu, sejumlah besar implementasi C library bersejarah memiliki fungsi stricmp () dan strnicmp (). Visual C ++ pada Windows mengganti nama semua ini dengan mengawali mereka dengan garis bawah karena mereka bukan bagian dari standar ANSI, jadi pada sistem itu mereka disebut _stricmp atau _strnicmp . Beberapa perpustakaan mungkin juga memiliki fungsi setara karakter lebar atau multibyte (biasanya dinamakan misalnya wcsicmp, mbcsicmp, dan sebagainya).
C dan C ++ sama-sama tidak mengetahui masalah internasionalisasi, jadi tidak ada solusi yang baik untuk masalah ini, kecuali menggunakan perpustakaan pihak ketiga. Periksa IBM ICU (Komponen Internasional untuk Unicode) jika Anda memerlukan pustaka yang kuat untuk C / C ++. ICU adalah untuk sistem Windows dan Unix.
sumber
Apakah Anda berbicara tentang membandingkan kasus bodoh bodoh atau Unicode penuh normalisasi?
Membandingkan bodoh tidak akan menemukan string yang mungkin sama tetapi tidak sama biner.
Contoh:
Semuanya setara tetapi mereka juga memiliki representasi biner yang berbeda.
Yang mengatakan, Normalisasi Unicode harus menjadi bacaan wajib terutama jika Anda berencana mendukung Hangul, Thailand dan bahasa asia lainnya.
Selain itu, IBM mematenkan algoritma Unicode yang paling optimal dan membuatnya tersedia untuk umum. Mereka juga mempertahankan implementasi: IBM ICU
sumber
boost :: iequals tidak kompatibel dengan utf-8 dalam hal string. Anda dapat menggunakan boost :: locale .
sumber
Pikiran pertama saya untuk versi non-unicode adalah melakukan sesuatu seperti ini:
sumber
Anda dapat menggunakan
strcasecmp
di Unix, ataustricmp
di Windows.Satu hal yang belum disebutkan sejauh ini adalah bahwa jika Anda menggunakan string stl dengan metode ini, ada baiknya untuk terlebih dahulu membandingkan panjang kedua string, karena informasi ini sudah tersedia untuk Anda di kelas string. Ini bisa mencegah melakukan perbandingan string yang mahal jika dua string yang Anda bandingkan bahkan tidak sama panjangnya.
sumber
Fungsi string Visual C ++ mendukung unicode: http://msdn.microsoft.com/en-us/library/cc194799.aspx
yang mungkin Anda cari adalah
_wcsnicmp
sumber
Saya mencoba menyusun jawaban yang baik dari semua posting, jadi bantu saya edit ini:
Berikut adalah metode untuk melakukan ini, meskipun itu mengubah string, dan tidak ramah Unicode, itu harus portabel yang merupakan nilai tambah:
Dari apa yang saya baca ini lebih portabel daripada stricmp () karena stricmp () sebenarnya bukan bagian dari perpustakaan std, tetapi hanya diimplementasikan oleh sebagian besar vendor kompiler.
Untuk mendapatkan implementasi yang benar-benar ramah Unicode tampaknya Anda harus pergi ke luar perpustakaan std. Satu perpustakaan pihak ketiga yang bagus adalah IBM ICU (Komponen Internasional untuk Unicode)
Juga meningkatkan :: iequals menyediakan utilitas yang cukup baik untuk melakukan perbandingan semacam ini.
sumber
transform
seluruh string sebelum perbandinganAnda dapat menggunakan kode di atas dalam C ++ 14 jika Anda tidak berada dalam posisi untuk menggunakan boost. Anda harus menggunakan
std::towlower
untuk karakter lebar.sumber
str1.size() == str2.size() &&
ke depan sehingga tidak akan keluar batas ketika str2 adalah awalan dari str1.The Boost.String perpustakaan memiliki banyak algoritma untuk melakukan hal-insenstive perbandingan dan sebagainya.
Anda bisa menerapkan sendiri, tetapi mengapa repot ketika itu sudah dilakukan?
sumber
FYI,
strcmp()
danstricmp()
rentan terhadap buffer overflow, karena mereka hanya memproses sampai mereka mencapai terminator nol. Lebih aman digunakan_strncmp()
dan_strnicmp()
.sumber
stricmp()
danstrnicmp()
bukan bagian dari standar POSIX :-( Namun Anda dapat menemukanstrcasecmp()
,strcasecmp_l()
,strncasecmp()
danstrncasecmp_l()
di POSIX sundulanstrings.h
:-) melihat opengroup.orgLihat
std::lexicographical_compare
:Demo
sumber
std::tolower
berfungsi hanya jika karakternya dikodekan ASCII. Tidak ada jaminan seperti itu untukstd::string
- sehingga perilaku itu tidak dapat didefinisikan dengan mudah.Untuk kebutuhan perbandingan string case sensitif dasar saya, saya lebih suka tidak harus menggunakan perpustakaan eksternal, saya juga tidak ingin kelas string terpisah dengan sifat-sifat case sensitif yang tidak kompatibel dengan semua string saya yang lain.
Jadi yang saya pikirkan adalah ini:
Fungsi sederhana dengan satu overload untuk char dan lainnya untuk whar_t. Tidak menggunakan apa pun yang tidak standar sehingga harus baik-baik saja pada platform apa pun.
Perbandingan kesetaraan tidak akan mempertimbangkan masalah seperti pengodean panjang variabel dan normalisasi Unicode, tetapi basic_string tidak memiliki dukungan untuk itu yang saya sadari dan itu biasanya bukan masalah.
Dalam kasus di mana manipulasi leksikografis yang lebih canggih dari teks diperlukan, maka Anda hanya harus menggunakan perpustakaan pihak ketiga seperti Boost, yang diharapkan.
sumber
Pendek dan bagus. Tidak ada dependensi lain, selain std C lib diperpanjang .
mengembalikan true jika
str1
danstr2
sama.strcasecmp
mungkin tidak ada, mungkin ada analogstricmp
,strcmpi
, dllKode contoh:
Keluaran:
sumber
stricmp
,strcmpi
,strcasecmp
, Dll Terima kasih. pesan diedit.cout << boolalpha
daripada sayabool2str
karena Ini untuk secara implisit mengkonversi bool ke karakter untuk streaming.Melakukan ini tanpa menggunakan Boost dapat dilakukan dengan mendapatkan pointer string C dengan
c_str()
dan menggunakanstrcasecmp
:sumber
Dengan asumsi Anda sedang mencari metode dan bukan fungsi sihir yang sudah ada, terus terang tidak ada cara yang lebih baik. Kita semua dapat menulis cuplikan kode dengan trik pintar untuk rangkaian karakter terbatas, tetapi pada akhirnya di suatu tempat Anda harus mengonversi karakter.
Pendekatan terbaik untuk konversi ini adalah melakukannya sebelum perbandingan. Ini memungkinkan Anda banyak fleksibilitas dalam hal skema penyandian, yang seharusnya tidak diperhatikan oleh operator perbandingan Anda.
Tentu saja Anda dapat 'menyembunyikan' konversi ini di belakang fungsi atau kelas string Anda sendiri, tetapi Anda masih perlu mengonversi string sebelum perbandingan.
sumber
Saya menulis versi char_traits case-insensitive untuk digunakan dengan std :: basic_string untuk menghasilkan string std :: yang tidak peka huruf besar-kecil ketika melakukan perbandingan, pencarian, dll menggunakan fungsi anggota std :: basic_string bawaan.
Jadi dengan kata lain, saya ingin melakukan sesuatu seperti ini.
... yang std :: string tidak dapat menangani. Inilah penggunaan char_traits baru saya:
... dan inilah implementasinya:
sumber
Saya memiliki pengalaman yang baik dalam menggunakan Komponen Internasional untuk pustaka Unicode - mereka sangat kuat, dan menyediakan metode untuk konversi, dukungan lokal, rendering tanggal dan waktu, pemetaan kasus (yang sepertinya tidak Anda inginkan), dan pengumpulan , yang mencakup perbandingan case-and-accentitive (dan banyak lagi). Saya hanya menggunakan versi C ++ dari pustaka, tetapi mereka tampaknya memiliki versi Java juga.
Ada metode untuk melakukan pembandingan yang dinormalisasi sebagaimana dimaksud oleh @Coincoin, dan bahkan dapat menjelaskan lokal - misalnya (dan ini contoh penyortiran, tidak sepenuhnya kesetaraan), secara tradisional dalam bahasa Spanyol (di Spanyol), kombinasi huruf "ll" akan memilah antara "l" dan "m", jadi "lz" <"ll" <"ma".
sumber
Cukup gunakan
strcmp()
untuk case sensitive danstrcmpi()
ataustricmp()
untuk case sensitive case. Yang keduanya di file header<string.h>
format:
Pemakaian:
Keluaran
apel dan ApPlE adalah sama
a datang sebelum b, jadi apel datang sebelum bola
sumber
Terlambat ke pesta, tetapi di sini ada varian yang menggunakan
std::locale
, dan dengan demikian menangani Turki dengan benar:memberi Anda functor yang menggunakan lokal aktif untuk mengonversi karakter menjadi huruf kecil, yang kemudian dapat Anda gunakan
std::transform
untuk menghasilkan string huruf kecil:Ini juga berfungsi untuk
wchar_t
string berbasis.sumber
Hanya catatan tentang metode apa pun yang akhirnya Anda pilih, jika metode itu terjadi termasuk penggunaan
strcmp
yang beberapa jawaban sarankan:strcmp
tidak bekerja dengan data Unicode secara umum. Secara umum, itu bahkan tidak bekerja dengan encode Unicode berbasis byte, seperti utf-8strcmp
hanya membuat perbandingan byte per byte dan titik kode Unicode yang dikodekan dalam utf-8 dapat membutuhkan lebih dari 1 byte. Satu-satunya kasus Unicode khusus yangstrcmp
ditangani dengan benar adalah ketika string yang dikodekan dengan pengkodean berbasis byte hanya berisi poin kode di bawah U + 00FF - maka perbandingan byte-per-byte sudah cukup.sumber
Pada awal 2013, proyek ICU, dikelola oleh IBM, adalah jawaban yang cukup bagus untuk ini.
http://site.icu-project.org/
ICU adalah "perpustakaan Unicode portabel yang lengkap yang secara ketat melacak standar industri." Untuk masalah spesifik perbandingan string, objek Collation melakukan apa yang Anda inginkan.
Proyek Mozilla mengadopsi ICU untuk internasionalisasi di Firefox pada pertengahan 2012; Anda dapat melacak diskusi teknik, termasuk masalah sistem pembangunan dan ukuran file data, di sini:
sumber
Sepertinya solusi di atas tidak menggunakan metode bandingkan dan menerapkan total lagi jadi di sini adalah solusi saya dan berharap itu berfungsi untuk Anda (Ini berfungsi dengan baik).
sumber
Jika Anda tidak ingin menggunakan perpustakaan Boost maka di sini ada solusi untuk itu hanya menggunakan header C ++ io standar.
sumber
Jika Anda harus membandingkan string sumber lebih sering dengan string lain, salah satu solusi elegan adalah menggunakan regex.
sumber
error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Cara sederhana untuk membandingkan dua string dalam c ++ (diuji untuk windows) adalah menggunakan _stricmp
Jika Anda ingin menggunakan dengan std :: string, contoh:
Untuk informasi lebih lanjut di sini: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx
sumber
ini mungkin bisa dibuat jauh lebih efisien, tetapi di sini ada versi besar dengan semua bitnya telanjang.
tidak semua yang portabel, tetapi bekerja dengan baik dengan apa pun yang ada di komputer saya (tidak tahu, saya gambar bukan kata-kata)
sumber
Cara mudah untuk membandingkan string yang hanya berbeda dengan huruf kecil dan huruf besar adalah dengan melakukan perbandingan ascii. Semua huruf besar dan kecil berbeda 32 bit dalam tabel ascii, menggunakan informasi ini kami memiliki ...
sumber