@ [Адам] (# 11679): Хотя этот вариант хорош с точки зрения удобства использования, он плох с точки зрения производительности, поскольку создает ненужные копии. Я мог бы что-то упустить, но я считаю, что лучший (не Unicode) способ это использовать std::stricmp. В противном случае, прочитайте, что Херб должен сказать .
Конрад Рудольф
В случае c обычно нужно перебирать всю строку, а затем сравнивать таким образом - или бросать собственное сравнение: P
@ Mσᶎ на этот вопрос также есть ответ, с важным предупреждением, strcasecmpкоторое не является частью стандарта и отсутствует по крайней мере в одном общем компиляторе.
Марк Рэнсом
Ответы:
318
Boost включает в себя удобный алгоритм для этого:
#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}
Нет, потому что UTF-8 позволяет кодировать идентичные строки с разными двоичными кодами из-за акцентов, сочетаний, проблем с биди и т. Д.
vy32
10
@ vy32 Это абсолютно неверно! Комбинации UTF-8 являются взаимоисключающими. Он всегда должен использовать кратчайшее возможное представление, если это не так, то это неправильно сформированная последовательность UTF-8 или кодовая точка, к которой следует обращаться с осторожностью.
Wiz
48
@Wiz, вы игнорируете проблему нормализации строки Unicode. ñ может быть представлен как комбинация ˜, за которой следует n или символ ñ. Вам необходимо использовать нормализацию строки Unicode перед выполнением сравнения. Пожалуйста , ознакомьтесь с Unicode Технический отчет № 15, unicode.org/reports/tr15
Воспользуйтесь преимуществом стандарта char_traits. Напомним , что std::stringэто на самом деле ЬурейеЕ для std::basic_string<char>или более явно, std::basic_string<char, std::char_traits<char> >. char_traitsТип описывает , как символы сравнить, как они копируют, как они бросают и т.д. Все , что нужно сделать , это ЬурейеЕ новую строку над basic_string, и предоставить его своим обычаем , char_traitsчто сравнить случай нечувствительно.
Насколько я знаю из моего собственного эксперимента, это делает ваш новый строковый тип несовместимым с std :: string.
Зан Рысь,
8
Конечно, это - для его же блага. Строка без учета регистра есть нечто другое: typedef std::basic_string<char, ci_char_traits<char> > istringне typedef std::basic_string<char, std::char_traits<char> > string.
Андреас Шпиндлер
232
«Все, что вам нужно сделать ...»
Тим М.Б.
3
@ Натан, вероятно, использует компилятор, который способен выполнять базовую CSE на коде ...
Парамагнитный круассан
17
Любая языковая конструкция, которая вызывает такое безумие в этом тривиальном случае, должна быть и может быть оставлена без сожалений.
Эрик Аронести
86
Проблема с бустом в том, что вы должны связываться с бустом и зависеть от него. Не легко в некоторых случаях (например, Android).
А использование char_traits означает, что все ваши сравнения нечувствительны к регистру, что обычно не то, что вам нужно.
Этого должно быть достаточно. Это должно быть достаточно эффективным. Не обрабатывает Unicode или что-то еще, хотя.
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;}
Обновление: Бонус C ++ 14 версия ( #include <algorithm>):
На самом деле, библиотека String String - это библиотека только для заголовков, поэтому нет необходимости ссылаться на что-либо. Кроме того, вы можете использовать утилиту boost 'bcp', чтобы скопировать только заголовки строк в ваше дерево исходных текстов, поэтому вам не требуется полная библиотека boost.
Гретхен
Ах, я не знал о BCP, это выглядит действительно полезным. Спасибо за информацию!
Тимммм
9
Полезно знать простую версию без зависимостей.
Deqing
2
@Anna Текстовая библиотека наддува должна быть построена и иметь ссылку. Он использует IBM ICU.
Behrouz.M
Также доступно с C ++ 11
марсианский
58
Если вы работаете в системе POSIX, вы можете использовать strcasecmp . Однако эта функция не является частью стандартного C и не доступна в Windows. Это будет выполнять сравнение без учета регистра для 8-битных символов, при условии, что языковой стандарт - POSIX. Если языковой стандарт не POSIX, результаты не определены (поэтому может выполняться локальное сравнение или нет). Эквивалент с широкими символами недоступен.
В противном случае большое количество исторических реализаций библиотеки C имеют функции stricmp () и strnicmp (). Visual C ++ в Windows переименовал все это, поставив перед ними подчеркивание, потому что они не являются частью стандарта ANSI, поэтому в этой системе они называются _stricmp или _strnicmp. . Некоторые библиотеки могут также иметь широко-символьные или многобайтовые эквивалентные функции (обычно называемые, например, wcsicmp, mbcsicmp и т. Д.).
C и C ++ в значительной степени не знают о проблемах интернационализации, поэтому у этой проблемы нет иного решения, кроме как использовать стороннюю библиотеку. Проверьте IBM ICU (Международные компоненты для Unicode), если вам нужна надежная библиотека для C / C ++. ICU для систем Windows и Unix.
Вы говорите о немом сравнении без учета регистра или полном нормализованном сравнении Unicode?
При немом сравнении не будут найдены строки, которые могут быть одинаковыми, но не равными двоичным.
Пример:
U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A)+ U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).
Все они эквивалентны, но они также имеют разные двоичные представления.
Тем не менее, Unicode нормализация должна быть обязательной для чтения, особенно если вы планируете поддерживать хангыль, тайский и другие азиатские языки.
Кроме того, IBM в значительной степени запатентовала наиболее оптимизированные алгоритмы Unicode и сделала их общедоступными. Они также поддерживают реализацию: IBM ICU
Вы можете использовать strcasecmpв Unix или stricmpWindows.
Одна вещь, которая до сих пор не упоминалась, это то, что если вы используете строки stl с этими методами, полезно сначала сравнить длину двух строк, так как эта информация уже доступна вам в классе строк. Это может помешать проведению дорогостоящего сравнения строк, если сравниваемые две строки имеют даже разную длину.
Поскольку определение длины строки состоит из итерации по каждому символу в строке и сравнения ее с 0, действительно ли так много различий между этим и просто сравнение строк сразу? Я предполагаю, что вы получаете лучшую локальность памяти в случае, когда обе строки не совпадают, но, вероятно, почти в 2 раза больше времени выполнения в случае совпадения.
Это забавный маленький факт, но здесь мало что значит. strcasecmp () и stricmp () принимают недекорированные строки C, поэтому в них не используется std :: string.
'39
3
Эти методы вернут -1, если вы сравните «a» с «ab». Длина различна, но «а» предшествует «а». Таким образом, простое сравнение длин не представляется возможным, если вызывающая сторона заботится о заказе.
Из того, что я прочитал, это более переносимо, чем stricmp (), потому что stricmp () на самом деле не является частью библиотеки std, а реализуется только большинством поставщиков компиляторов.
Чтобы получить действительно дружественную для Unicode реализацию, кажется, вы должны выйти за пределы библиотеки std. Одна хорошая сторонняя библиотека - IBM ICU (Международные компоненты для Unicode)
Также boost :: iequals предоставляет довольно хорошую утилиту для такого рода сравнения.
Вы можете использовать приведенный выше код на C ++ 14, если вы не в состоянии использовать boost. Вы должны использовать std::towlowerдля широких символов.
"... зачем, когда это уже сделано?" - что делать, если вы не используете Boost? У ОП не было тега с вопросом.
jww
11
К вашему сведению, strcmp()и stricmp()уязвимы для переполнения буфера, поскольку они просто обрабатывают, пока не достигнут нулевого терминатора. Безопаснее использовать _strncmp()и _strnicmp().
Правда, хотя перезапись буфера значительно менее опасна, чем перезапись буфера.
Адам Розенфилд
4
stricmp()и strnicmp()не являются частью стандарта POSIX :-( Однако вы можете найти strcasecmp(), strcasecmp_l(), strncasecmp()и strncasecmp_l()в заголовке POSIX strings.h:-) см opengroup.org
olibre
2
@AdamRosenfield «хуже» зависит от контекста. В области безопасности иногда весь смысл перезаписи заключается в том, чтобы перезаписать.
Этот метод потенциально небезопасен и непереносим. std::tolowerработает, только если символ в кодировке ASCII. Нет такой гарантии для std::string- так что это может быть неопределенное поведение легко.
plasmacel
@plasmacel Затем используйте функцию, которая работает с другими кодировками.
Брайан Родригес
9
Для моих базовых потребностей сравнения строк без учета регистра я предпочитаю не использовать внешнюю библиотеку, и при этом я не хочу отдельного класса строк с характеристиками без учета регистра, которые несовместимы со всеми моими другими строками.
Простая функция с одной перегрузкой для char и другой для whar_t. Не использует ничего нестандартного, поэтому должно работать на любой платформе.
Сравнение на равенство не учитывает такие проблемы, как кодирование переменной длины и нормализация Unicode, но basic_string не поддерживает этого, о чем я все равно знаю, и обычно это не проблема.
В тех случаях, когда требуется более сложное лексикографическое манипулирование текстом, вам просто нужно использовать стороннюю библиотеку, такую как Boost, что и следовало ожидать.
Вы могли бы сделать эту функцию, если бы сделали ее шаблоном и использовали basic_string <T> вместо отдельных версий string / wstring?
Uliwitness
2
Как бы один шаблон функции вызывал toupper или towupper без использования специализации или макросов, перегрузка функции кажется более простой и более подходящей реализацией, чем любая из них.
Нейтрино
9
Коротко и красиво. Никаких других зависимостей, кроме расширенных стандартных C lib.
strcasecmp(str1.c_str(), str2.c_str())==0
возвращает true, если str1и str2равны.
strcasecmpможет не существовать, не может быть аналогами stricmp, strcmpiи т.д.
Пример кода:
#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;}
Предполагая, что вы ищете метод, а не волшебную функцию, которая уже существует, откровенно говоря, лучшего способа нет. Мы все могли бы написать фрагменты кода с умными трюками для ограниченных наборов символов, но в конце дня в какой-то момент вы должны преобразовать символы.
Лучший подход для этого преобразования - сделать это до сравнения. Это дает вам большую гибкость, когда речь идет о схемах кодирования, о которых ваш действительный оператор сравнения должен не знать.
Конечно, вы можете «скрыть» это преобразование за своей собственной строковой функцией или классом, но вам все равно нужно преобразовать строки перед сравнением.
Я написал версию char_traits без учета регистра для использования с std :: basic_string, чтобы сгенерировать std :: string, которая не учитывает регистр при сравнении, поиске и т. Д. С использованием встроенных функций-членов std :: basic_string.
Другими словами, я хотел сделать что-то подобное.
std::string a ="Hello, World!";
std::string b ="hello, world!";
assert( a == b );
... который std :: string не может обработать Вот использование моего нового char_traits:
std::istring a ="Hello, World!";
std::istring b ="hello, world!";
assert( a == b );
... и вот реализация:
/* ---
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;
Это работает для обычных символов, но не будет работать для всего Unicode, поскольку капитализация не обязательно является двунаправленной (есть хороший пример греческого языка с сигмой, который я не могу вспомнить сейчас; что-то вроде этого имеет два нижних и один верхний регистр , и вы не можете получить надлежащее сравнение в любом случае)
Коппро
1
Это действительно неправильный путь. Чувствительность к регистру не должна быть свойством самих строк. Что происходит, когда один и тот же строковый объект нуждается в сравнении с учетом регистра и без учета регистра?
Ферруччо
Если чувствительность к регистру не подходит, чтобы быть «частью» строки, тогда ни одна из них не является функцией find (). Что для вас может быть правдой, и это нормально. ИМО самое главное в C ++ - это то, что он не навязывает определенную парадигму программисту. Это то, что вы хотите / нужно, чтобы это было.
Джон Диблинг
На самом деле, я думаю, что большинство C ++ - гуру (например, те, что входят в комитет по стандартам) согласны с тем, что было ошибкой помещать find () в std :: basic_string <> вместе с целым рядом других вещей, которые с таким же успехом можно было бы поместить в свободные функции. Кроме того, есть некоторые проблемы с помещением этого типа.
Андреас Магнуссон
Как уже отмечали другие, в этом решении есть две основные проблемы (по иронии судьбы, одна - это интерфейс, а другая - реализация ;-)).
Конрад Рудольф
4
У меня был хороший опыт использования библиотек International Components for Unicode - они чрезвычайно мощные и предоставляют методы для преобразования, поддержки локали, рендеринга даты и времени, отображения дел (что вам не нужно) и сопоставления , который включает сравнение без учета регистра и акцента (и многое другое). Я использовал только версию библиотек на C ++, но, похоже, они также имеют версию Java.
Существуют методы для выполнения нормализованных сравнений, на которые ссылается @Coincoin, и они могут даже учитывать локаль - например (и это пример сортировки, а не строго равенство), традиционно на испанском языке (в Испании) комбинация букв «ll» сортирует между "l" и "m", поэтому "lz" <"ll" <"ma".
Просто используйте strcmp()для чувствительности к регистру и strcmpi()или stricmp()для сравнения без учета регистра. Которые оба в заголовочном файле<string.h>
формат:
int strcmp(constchar*,constchar*);//for case sensitiveint strcmpi(constchar*,constchar*);//for case insensitive
Применение:
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;
Downvote, потому что это вряд ли C ++ способ делать вещи.
Томас Дауго
Это соглашение c ++ в моем университете, но я буду помнить его при публикации здесь
reubenjohn
4
stricmp является расширением Microsoft AFAIK. В BSD вместо этого используется strcasecmp ().
Uliwitness
3
Поздно до вечеринки, но вот вариант, который использует std::localeи, следовательно, правильно обрабатывает турецкий язык:
auto tolower = std::bind1st(
std::mem_fun(&std::ctype<char>::tolower),&std::use_facet<std::ctype<char>>(
std::locale()));
дает вам функтор, который использует активную локаль для преобразования символов в нижний регистр, который затем можно использовать с помощью std::transformдля генерации строчных букв:
std::string left ="fOo";
transform(left.begin(), left.end(), left.begin(), tolower);
Просто заметка о том, какой метод вы в конечном итоге выберете, если этот метод включает использование того, strcmpчто некоторые ответы предлагают:
strcmpне работает с данными Unicode в целом. В общем, он даже не работает с байтовыми кодировками Unicode, такими как utf-8, поскольку strcmpтолько сравнение байтов за байтом, а кодовые точки Unicode, кодированные в utf-8, могут занимать более 1 байта. Единственный конкретный случай Unicode, который strcmpправильно обрабатывается, - это когда строка, закодированная с помощью байтовой кодировки, содержит только кодовые точки ниже U + 00FF - тогда достаточно сравнения байтов на байты.
ICU - это «полная, портативная библиотека Unicode, которая точно соответствует отраслевым стандартам». Для конкретной задачи сравнения строк объект Collation делает то, что вы хотите.
Проект Mozilla принял ICU для интернационализации в Firefox в середине 2012 года; Вы можете отслеживать технические обсуждения, в том числе вопросы систем сборки и размера файла данных, здесь:
Похоже, что вышеупомянутые решения не используют метод сравнения и снова реализуют итоги, так что вот мое решение и надеюсь, что оно работает для вас (работает нормально).
Если вы не хотите использовать библиотеку Boost, вот решение этой проблемы, использующее только стандартный C ++ заголовок io.
#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;}
Я считаю, что std :: toupper находится в #include <cctype>, возможно, вам придется включить его.
Дэвид Леджер
Если вы будете использовать глобальную версию наподобие this :: toupper, то вам, возможно, не потребуется включать <ctype>, потому что есть две версии c версия и версия c ++ с локалью, я думаю. Поэтому лучше использовать глобальную версию ":: toupper ()"
HaSeeB MiR
это решение завершается ошибкой, когда одна из строк пуста: "" - возвращает true в том случае, если оно должно возвращать false
ekkis
0
Если вам приходится сравнивать исходную строку чаще с другими строками, одним из элегантных решений является использование регулярных выражений.
std::wstring first = L"Test";
std::wstring second = L"TEST";
std::wregex pattern(first, std::wregex::icase);bool isEqual = std::regex_match(second, pattern);
Пробовал это, но ошибка компиляции: error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Deqing
плохая идея. Это худшее решение.
Behrouz.M
Это не очень хорошее решение, но даже если вы хотите его использовать, вам нужен L перед вашими самыми широкими константами, например, L "TEST"
celticminstrel
Было бы хорошо, если бы кто-то мог объяснить, почему это худшее решение. Из-за проблем с производительностью? Создание регулярных выражений стоит дорого, но после этого сравнение должно быть очень быстрым.
smibe
он удобен в использовании и переносим, основная проблема в том, что сначала он не может содержать символы, используемые регулярным выражением. Из-за этого его нельзя использовать в качестве общего сравнения строк. Это также будет медленнее, есть флаг, который заставляет его работать так, как говорит smibe, но все еще не может использоваться как общая функция.
Бен
0
Простой способ сравнить две строки в c ++ (протестировано для Windows) - использовать _stricmp
// Case insensitive (could use equivalent _stricmp)
result = _stricmp( string1, string2 );
Если вы хотите использовать std :: string, например:
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;}}}
это, вероятно, можно сделать гораздо более эффективным, но вот громоздкая версия со всеми ее битами.
не такой портативный, но хорошо работает с тем, что есть на моем компьютере (не знаю, я из картинок, а не слов)
Это не поддержка Unicode, которая задается вопросом.
Behrouz.M
Это не поддерживает неанглийские наборы символов.
Роберт Анджеюк
-3
Простой способ сравнения строк, которые различаются только строчными и прописными буквами, состоит в сравнении ascii. Все заглавные и строчные буквы различаются на 32 бита в таблице ascii, используя эту информацию, мы имеем следующее ...
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
. В противном случае, прочитайте, что Херб должен сказать .strcasecmp
которое не является частью стандарта и отсутствует по крайней мере в одном общем компиляторе.Ответы:
Boost включает в себя удобный алгоритм для этого:
источник
Воспользуйтесь преимуществом стандарта
char_traits
. Напомним , чтоstd::string
это на самом деле ЬурейеЕ дляstd::basic_string<char>
или более явно,std::basic_string<char, std::char_traits<char> >
.char_traits
Тип описывает , как символы сравнить, как они копируют, как они бросают и т.д. Все , что нужно сделать , это ЬурейеЕ новую строку надbasic_string
, и предоставить его своим обычаем ,char_traits
что сравнить случай нечувствительно.Подробности на Гуру Недели № 29 .
источник
typedef std::basic_string<char, ci_char_traits<char> > istring
неtypedef std::basic_string<char, std::char_traits<char> > string
.Проблема с бустом в том, что вы должны связываться с бустом и зависеть от него. Не легко в некоторых случаях (например, Android).
А использование char_traits означает, что все ваши сравнения нечувствительны к регистру, что обычно не то, что вам нужно.
Этого должно быть достаточно. Это должно быть достаточно эффективным. Не обрабатывает Unicode или что-то еще, хотя.
Обновление: Бонус C ++ 14 версия (
#include <algorithm>
):источник
Если вы работаете в системе POSIX, вы можете использовать strcasecmp . Однако эта функция не является частью стандартного C и не доступна в Windows. Это будет выполнять сравнение без учета регистра для 8-битных символов, при условии, что языковой стандарт - POSIX. Если языковой стандарт не POSIX, результаты не определены (поэтому может выполняться локальное сравнение или нет). Эквивалент с широкими символами недоступен.
В противном случае большое количество исторических реализаций библиотеки C имеют функции stricmp () и strnicmp (). Visual C ++ в Windows переименовал все это, поставив перед ними подчеркивание, потому что они не являются частью стандарта ANSI, поэтому в этой системе они называются _stricmp или _strnicmp. . Некоторые библиотеки могут также иметь широко-символьные или многобайтовые эквивалентные функции (обычно называемые, например, wcsicmp, mbcsicmp и т. Д.).
C и C ++ в значительной степени не знают о проблемах интернационализации, поэтому у этой проблемы нет иного решения, кроме как использовать стороннюю библиотеку. Проверьте IBM ICU (Международные компоненты для Unicode), если вам нужна надежная библиотека для C / C ++. ICU для систем Windows и Unix.
источник
Вы говорите о немом сравнении без учета регистра или полном нормализованном сравнении Unicode?
При немом сравнении не будут найдены строки, которые могут быть одинаковыми, но не равными двоичным.
Пример:
Все они эквивалентны, но они также имеют разные двоичные представления.
Тем не менее, Unicode нормализация должна быть обязательной для чтения, особенно если вы планируете поддерживать хангыль, тайский и другие азиатские языки.
Кроме того, IBM в значительной степени запатентовала наиболее оптимизированные алгоритмы Unicode и сделала их общедоступными. Они также поддерживают реализацию: IBM ICU
источник
boost :: iequals не совместим с utf-8 в случае строки. Вы можете использовать boost :: locale .
источник
Моей первой мыслью для не-Unicode-версии было сделать что-то вроде этого:
источник
Вы можете использовать
strcasecmp
в Unix илиstricmp
Windows.Одна вещь, которая до сих пор не упоминалась, это то, что если вы используете строки stl с этими методами, полезно сначала сравнить длину двух строк, так как эта информация уже доступна вам в классе строк. Это может помешать проведению дорогостоящего сравнения строк, если сравниваемые две строки имеют даже разную длину.
источник
Строковые функции Visual C ++, поддерживающие Юникод: http://msdn.microsoft.com/en-us/library/cc194799.aspx
тот, который вы, вероятно, ищете
_wcsnicmp
источник
Я пытаюсь собрать хороший ответ из всех постов, поэтому помогите мне отредактировать это:
Вот способ сделать это, хотя он преобразует строки и не поддерживает Unicode, он должен быть переносимым, что является плюсом:
Из того, что я прочитал, это более переносимо, чем stricmp (), потому что stricmp () на самом деле не является частью библиотеки std, а реализуется только большинством поставщиков компиляторов.
Чтобы получить действительно дружественную для Unicode реализацию, кажется, вы должны выйти за пределы библиотеки std. Одна хорошая сторонняя библиотека - IBM ICU (Международные компоненты для Unicode)
Также boost :: iequals предоставляет довольно хорошую утилиту для такого рода сравнения.
источник
transform
всю строку перед сравнениемВы можете использовать приведенный выше код на C ++ 14, если вы не в состоянии использовать boost. Вы должны использовать
std::towlower
для широких символов.источник
str1.size() == str2.size() &&
вперед, чтобы не выходить за пределы, когда str2 является префиксом str1.В библиотеке Boost.String имеется множество алгоритмов для сравнения без учета регистра и так далее.
Вы могли бы реализовать свой собственный, но зачем беспокоиться, когда это уже сделано?
источник
К вашему сведению,
strcmp()
иstricmp()
уязвимы для переполнения буфера, поскольку они просто обрабатывают, пока не достигнут нулевого терминатора. Безопаснее использовать_strncmp()
и_strnicmp()
.источник
stricmp()
иstrnicmp()
не являются частью стандарта POSIX :-( Однако вы можете найтиstrcasecmp()
,strcasecmp_l()
,strncasecmp()
иstrncasecmp_l()
в заголовке POSIXstrings.h
:-) см opengroup.orgСмотрите
std::lexicographical_compare
:демонстрация
источник
std::tolower
работает, только если символ в кодировке ASCII. Нет такой гарантии дляstd::string
- так что это может быть неопределенное поведение легко.Для моих базовых потребностей сравнения строк без учета регистра я предпочитаю не использовать внешнюю библиотеку, и при этом я не хочу отдельного класса строк с характеристиками без учета регистра, которые несовместимы со всеми моими другими строками.
Итак, что я придумал, это:
Простая функция с одной перегрузкой для char и другой для whar_t. Не использует ничего нестандартного, поэтому должно работать на любой платформе.
Сравнение на равенство не учитывает такие проблемы, как кодирование переменной длины и нормализация Unicode, но basic_string не поддерживает этого, о чем я все равно знаю, и обычно это не проблема.
В тех случаях, когда требуется более сложное лексикографическое манипулирование текстом, вам просто нужно использовать стороннюю библиотеку, такую как Boost, что и следовало ожидать.
источник
Коротко и красиво. Никаких других зависимостей, кроме расширенных стандартных C lib.
возвращает true, если
str1
иstr2
равны.strcasecmp
может не существовать, не может быть аналогамиstricmp
,strcmpi
и т.д.Пример кода:
Вывод:
источник
stricmp
,strcmpi
,strcasecmp
И т.д. Спасибо. Сообщение отредактировано.cout << boolalpha
вместо my,bool2str
потому что он неявно конвертирует bool в chars для stream.Сделать это без использования Boost можно, получив указатель на строку C с
c_str()
помощьюstrcasecmp
:источник
Предполагая, что вы ищете метод, а не волшебную функцию, которая уже существует, откровенно говоря, лучшего способа нет. Мы все могли бы написать фрагменты кода с умными трюками для ограниченных наборов символов, но в конце дня в какой-то момент вы должны преобразовать символы.
Лучший подход для этого преобразования - сделать это до сравнения. Это дает вам большую гибкость, когда речь идет о схемах кодирования, о которых ваш действительный оператор сравнения должен не знать.
Конечно, вы можете «скрыть» это преобразование за своей собственной строковой функцией или классом, но вам все равно нужно преобразовать строки перед сравнением.
источник
Я написал версию char_traits без учета регистра для использования с std :: basic_string, чтобы сгенерировать std :: string, которая не учитывает регистр при сравнении, поиске и т. Д. С использованием встроенных функций-членов std :: basic_string.
Другими словами, я хотел сделать что-то подобное.
... который std :: string не может обработать Вот использование моего нового char_traits:
... и вот реализация:
источник
У меня был хороший опыт использования библиотек International Components for Unicode - они чрезвычайно мощные и предоставляют методы для преобразования, поддержки локали, рендеринга даты и времени, отображения дел (что вам не нужно) и сопоставления , который включает сравнение без учета регистра и акцента (и многое другое). Я использовал только версию библиотек на C ++, но, похоже, они также имеют версию Java.
Существуют методы для выполнения нормализованных сравнений, на которые ссылается @Coincoin, и они могут даже учитывать локаль - например (и это пример сортировки, а не строго равенство), традиционно на испанском языке (в Испании) комбинация букв «ll» сортирует между "l" и "m", поэтому "lz" <"ll" <"ma".
источник
Просто используйте
strcmp()
для чувствительности к регистру иstrcmpi()
илиstricmp()
для сравнения без учета регистра. Которые оба в заголовочном файле<string.h>
формат:
Применение:
Вывод
яблоко и яблоко одинаковы
а до б, поэтому яблоко до мяча
источник
Поздно до вечеринки, но вот вариант, который использует
std::locale
и, следовательно, правильно обрабатывает турецкий язык:дает вам функтор, который использует активную локаль для преобразования символов в нижний регистр, который затем можно использовать с помощью
std::transform
для генерации строчных букв:Это также работает для
wchar_t
основанных строк.источник
Просто заметка о том, какой метод вы в конечном итоге выберете, если этот метод включает использование того,
strcmp
что некоторые ответы предлагают:strcmp
не работает с данными Unicode в целом. В общем, он даже не работает с байтовыми кодировками Unicode, такими как utf-8, посколькуstrcmp
только сравнение байтов за байтом, а кодовые точки Unicode, кодированные в utf-8, могут занимать более 1 байта. Единственный конкретный случай Unicode, которыйstrcmp
правильно обрабатывается, - это когда строка, закодированная с помощью байтовой кодировки, содержит только кодовые точки ниже U + 00FF - тогда достаточно сравнения байтов на байты.источник
На начало 2013 года проект ICU, поддерживаемый IBM, является довольно хорошим ответом на это.
http://site.icu-project.org/
ICU - это «полная, портативная библиотека Unicode, которая точно соответствует отраслевым стандартам». Для конкретной задачи сравнения строк объект Collation делает то, что вы хотите.
Проект Mozilla принял ICU для интернационализации в Firefox в середине 2012 года; Вы можете отслеживать технические обсуждения, в том числе вопросы систем сборки и размера файла данных, здесь:
источник
Похоже, что вышеупомянутые решения не используют метод сравнения и снова реализуют итоги, так что вот мое решение и надеюсь, что оно работает для вас (работает нормально).
источник
Если вы не хотите использовать библиотеку Boost, вот решение этой проблемы, использующее только стандартный C ++ заголовок io.
источник
Если вам приходится сравнивать исходную строку чаще с другими строками, одним из элегантных решений является использование регулярных выражений.
источник
error: conversion from 'const char [5]' to non-scalar type 'std::wstring {aka std::basic_string<wchar_t>}' requested
Простой способ сравнить две строки в c ++ (протестировано для Windows) - использовать _stricmp
Если вы хотите использовать std :: string, например:
Для получения дополнительной информации здесь: https://msdn.microsoft.com/it-it/library/e0z9k731.aspx
источник
это, вероятно, можно сделать гораздо более эффективным, но вот громоздкая версия со всеми ее битами.
не такой портативный, но хорошо работает с тем, что есть на моем компьютере (не знаю, я из картинок, а не слов)
источник
Простой способ сравнения строк, которые различаются только строчными и прописными буквами, состоит в сравнении ascii. Все заглавные и строчные буквы различаются на 32 бита в таблице ascii, используя эту информацию, мы имеем следующее ...
источник