C ++中不区分大小写的字符串比较[关闭]


373

在C ++中进行不区分大小写的字符串比较而不将字符串转换为全部大写或全部小写的最佳方法是什么?

请指出这些方法是否支持Unicode,以及它们的可移植性。


@ [Adam](#11679):尽管此变体在可用性方面不错,但在性能方面却很糟糕,因为它会创建不必要的副本。我可能会忽略一些东西,但是我相信最好的(非Unicode)方法是使用std::stricmp。否则,请阅读赫伯必须说的话
Konrad Rudolph

在c语言中,通常会强迫整个字符串加粗,然后以这种方式进行比较-或进行自己的比较:P
Michael Dorgan

以后的问题有一个简单的答案:strcasecmp(至少对于BSD和POSIX的编译器)stackoverflow.com/questions/9182912/...
莫兹

@Mσᶎ这个问题也有答案,但重要的警告strcasecmp不是该标准的一部分,并且至少在一个常用的编译器中缺少。
Mark Ransom 2014年

Answers:


317

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
}

14
这是UTF-8友好的吗?我想不是。
vladr

18
没有,因为UTF-8允许相同的字符串与不同的二进制码进行编码,由于重音,联合收割机,比迪问题等
vy32

10
@ vy32绝对不正确!UTF-8组合互斥。它必须始终使用尽可能最短的表示形式,如果没有,则必须使用格式错误的UTF-8序列或代码点。
Wiz

48
@Wiz,您将忽略Unicode字符串标准化的问题。ñ可以表示为一个组合〜,后跟n或一个ñ字符。在执行比较之前,您需要使用Unicode字符串规范化。请查看Unicode技术报告#15, unicode.org
reports /

12
@wonkorealtime:因为“ß”转换为大写字母是“ SS”:fileformat.info/info/unicode/char/df/index.htm
Mooing Duck

118

利用标准char_traits。回想一下,a std::string实际上是的类型定义std::basic_string<char>,或更明确地说是std::basic_string<char, std::char_traits<char> >。该char_traits类型描述字符如何进行比较,如何复制,如何进行转换等。您需要做的就是在上basic_string定义一个新字符串,并为您提供一个自己的自定义字符,以char_traits不区分大小写的方式进行比较。

struct ci_char_traits : public char_traits<char> {
    static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
    static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
    static bool lt(char c1, char c2) { return toupper(c1) <  toupper(c2); }
    static int compare(const char* s1, const char* s2, size_t n) {
        while( n-- != 0 ) {
            if( toupper(*s1) < toupper(*s2) ) return -1;
            if( toupper(*s1) > toupper(*s2) ) return 1;
            ++s1; ++s2;
        }
        return 0;
    }
    static const char* find(const char* s, int n, char a) {
        while( n-- > 0 && toupper(*s) != toupper(a) ) {
            ++s;
        }
        return s;
    }
};

typedef std::basic_string<char, ci_char_traits> ci_string;

有关详细信息,请参见“本周大师29”


10
据我自己的实验了解,这会使您的新字符串类型与std :: string不兼容。
Zan Lynx 2012年

8
当然可以-为了自己的利益。不区分大小写的字符串是:typedef std::basic_string<char, ci_char_traits<char> > istring,不是typedef std::basic_string<char, std::char_traits<char> > string
安德里亚斯·斯平德勒

232
“您需要做的一切……”
Tim MB

3
@Nathan可能使用的是能够在代码上执行基本CSE的编译器...
顺磁牛角包2014年

17
在这种琐碎的情况下,任何导致这种精神错乱的语言构造都应该并且可以被抛弃而不会后悔。
Erik Aronesty,2014年

86

Boost的问题在于您必须链接并依赖Boost。在某些情况下(例如android)并不容易。

使用char_traits意味着所有比较都不区分大小写,通常这不是您想要的。

这样就足够了。它应该是合理有效的。虽然不处理unicode或其他任何东西。

bool iequals(const string& a, const string& b)
{
    unsigned int sz = a.size();
    if (b.size() != sz)
        return false;
    for (unsigned int i = 0; i < sz; ++i)
        if (tolower(a[i]) != tolower(b[i]))
            return false;
    return true;
}

更新:Bonus C ++ 14版本(#include <algorithm>):

bool iequals(const string& a, const string& b)
{
    return std::equal(a.begin(), a.end(),
                      b.begin(), b.end(),
                      [](char a, char b) {
                          return tolower(a) == tolower(b);
                      });
}

27
实际上,boost字符串库是仅标头的库,因此无需链接到任何内容。另外,您可以使用boost的'bcp'实用程序将字符串标头仅复制到源代码树中,因此您不需要完整的boost库。
Gretchen

啊,我不知道bcp,它看起来真的很有用。谢谢(你的)信息!
Timmmm 2011年

9
很高兴知道一个简单且非依赖提升的版本。
德庆2014年

2
@Anna需要构建boost文本库并进行链接。它使用IBM ICU。
Behrouz.M 2015年

也可用于C ++ 11
火星人

58

如果您使用的是POSIX系统,则可以使用strcasecmp。但是,此功能不是标准C的一部分,在Windows上也不可用。只要语言环境为POSIX,这将对8位字符执行不区分大小写的比较。如果语言环境不是POSIX,则结果是不确定的(因此它可能会进行本地化比较,也可能不会)。不能使用宽字符等效项。

失败的是,许多历史悠久的C库实现都具有函数stricmp()和strnicmp()。Windows上的Visual C ++将所有这些都重命名为下划线,因为它们不是ANSI标准的一部分,因此在该系统上,它们被称为_stricmp或_strnicmp。一些库可能还具有宽字符或多字节等效功能(通常命名为例如wcsicmp,mbcsicmp等)。

C和C ++都对国际化问题一无所知,因此,除了使用第三方库以外,没有很好的解决方案。如果需要用于C / C ++的强大库,请签出IBM ICU(Unicode国际组件)。ICU适用于Windows和Unix系统。


53

您是在说不区分大小写的哑比较还是完全规范化的Unicode比较?

愚蠢的比较不会找到可能相同但不等于二进制的字符串。

例:

U212B (ANGSTROM SIGN)
U0041 (LATIN CAPITAL LETTER A) + U030A (COMBINING RING ABOVE)
U00C5 (LATIN CAPITAL LETTER A WITH RING ABOVE).

都是等效的,但它们也具有不同的二进制表示形式。

就是说,Unicode规范化应该是强制性阅读,尤其是如果您计划支持韩文,Thaï和其他亚洲语言。

此外,IBM几乎为最优化的Unicode算法申请了专利,并使其公开可用。他们还维护一个实现:IBM ICU


2
您可能需要编辑ICU链接到site.icu-project.org
DevSolar

31

对于字符串,boost :: iequals不兼容utf-8。您可以使用boost :: locale

comparator<char,collator_base::secondary> cmpr;
cout << (cmpr(str1, str2) ? "str1 < str2" : "str1 >= str2") << endl;
  • 主要-忽略重音符号和字符大小写,仅比较基本字母。例如,“ facade”和“Façade”是相同的。
  • 次要的-忽略字符大小写,但考虑重音符号。“外观”和“外观”不同,但“外观”和“外观”相同。
  • 大专-兼顾大小写和重音:“外观”和“外观”是不同的。忽略标点符号。
  • 第四纪-考虑所有大小写,重音和标点符号。这些单词在Unicode表示形式上必须相同。
  • 相同-作为四元数,但也比较代码点。

30

对于非unicode版本,我的第一个想法是执行以下操作:


bool caseInsensitiveStringCompare(const string& str1, const string& str2) {
    if (str1.size() != str2.size()) {
        return false;
    }
    for (string::const_iterator c1 = str1.begin(), c2 = str2.begin(); c1 != str1.end(); ++c1, ++c2) {
        if (tolower(*c1) != tolower(*c2)) {
            return false;
        }
    }
    return true;
}

20

您可以strcasecmp在Unix或stricmpWindows上使用。

到目前为止尚未提及的一件事是,如果您在这些方法中使用stl字符串,则首先比较两个字符串的长度很有用,因为在字符串类中已经可以使用此信息。如果您要比较的两个字符串最初的长度甚至不相同,则可以避免进行昂贵的字符串比较。


由于确定字符串的长度包括对字符串中的每个字符进行迭代并将其与0进行比较,因此与立即比较字符串之间是否真的有那么大的区别?我猜想在两个字符串都不匹配的情况下,您可以获得更好的内存局部性,但是在匹配的情况下,运行时间可能会接近2倍。
uliwitness 2014年

3
C ++ 11指定std :: string :: length的复杂度必须恒定:cplusplus.com/reference/string/string/length
bradtgmurray

1
这是一个有趣的小事实,但是没有什么意义。strcasecmp()和stricmp()都采用未修饰的C字符串,因此不涉及std :: string。
uliwitness 2014年

3
如果您比较“ a”和“ ab”,这些方法将返回-1。长度不同,但是“ a”在“ ab”之前。因此,如果呼叫者关心订购,简单地比较长度是不可行的。
内森


13

我正在尝试从所有帖子中收集一个好的答案,所以请帮助我编辑一下:

这是一种执行此操作的方法,尽管它确实可以转换字符串,并且不支持Unicode,但它应该是可移植的,这是一个加号:

bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
    std::string str1Cpy( str1 );
    std::string str2Cpy( str2 );
    std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
    std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
    return ( str1Cpy == str2Cpy );
}

根据我的阅读,这比stricmp()更可移植,因为stricmp()实际上不是std库的一部分,而仅由大多数编译器供应商实现。

为了获得真正的Unicode友好实现,您似乎必须在std库之外。一个很好的第三方库是IBM ICU(Unicode国际组件)

另外的boost :: iequals提供了做这种比较的一个相当不错的实用性。


您能告诉我:: tolower是什么意思,为什么可以使用tolower代替tolower(),以及以前的'::'是什么?谢谢
VextoR 2011年

17
这不是一个非常有效的解决方案-即使第一个字符不同,也要复制两个字符串并转换所有字符串。
Timmmm 2011年

2
如果仍然要进行复制,为什么不按值而不是按引用传递呢?
celticminstrel 2015年

我认为这是简单的秘诀,无助益。:)
cmcromance

1
这个问题明确要求transform在比较之前不是整个字符串
Sandburg

12
str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](auto a, auto b){return std::tolower(a)==std::tolower(b);})

如果您无法使用boost,则可以在C ++ 14中使用以上代码。您必须使用std::towlower宽字符。


4
我认为您需要str1.size() == str2.size() &&在前面添加a ,以便当str2是str1的前缀时不会超出范围。
ɲeuroburɳ

11

Boost.String图书馆有很多算法做案例insenstive比较等。

您可以实现自己的实现,但是为什么要花些时间呢?


1
std :: string没有内置的方法吗?
WilliamKF 2010年

6
不,没有。
迪恩·哈丁

3
“……为什么要花点时间完成呢?” -如果您不使用Boost怎么办?OP没有带有问题的标签。
jww '16

11

仅供参考,strcmp()并且stricmp()容易受到缓冲区溢出的影响,因为它们只会处理直到遇到空终止符为止。使用_strncmp()和更安全_strnicmp()


6
的确如此,尽管过度读取缓冲区的危险远低于过度写入缓冲区的危险。
亚当·罗森菲尔德

4
stricmp()strnicmp()不是POSIX标准的一部分:-(但是你可以找到strcasecmp()strcasecmp_l()strncasecmp()strncasecmp_l()在POSIX头strings.h:-)看看opengroup.org
olibre

2
@AdamRosenfield的“更差”取决于上下文。在安全性方面,有时覆盖的全部目的是要过度阅读。
karmakaze 2015年

10

std::lexicographical_compare

// lexicographical_compare example
#include <iostream>  // std::cout, std::boolalpha
#include <algorithm>  // std::lexicographical_compare
#include <cctype>  // std::tolower

// a case-insensitive comparison function:
bool mycomp (char c1, char c2) {
    return std::tolower(c1) < std::tolower(c2);
}

int main () {
    char foo[] = "Apple";
    char bar[] = "apartment";

    std::cout << std::boolalpha;

    std::cout << "Comparing foo and bar lexicographically (foo < bar):\n";

    std::cout << "Using default comparison (operator<): ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9);
    std::cout << '\n';

    std::cout << "Using mycomp as comparison object: ";
    std::cout << std::lexicographical_compare(foo, foo + 5, bar, bar + 9, mycomp);
    std::cout << '\n';

    return 0;
}

演示版


此方法可能不安全且不可移植。std::tolower仅当字符是ASCII编码时才有效。没有这样的保证std::string-因此它很容易成为未定义的行为。
–plasmcel

@plasmacel然后使用可以使用其他编码的函数。
布赖恩·罗德里格斯

9

对于我的基本不区分大小写的字符串比较需求,我不想不必使用外部库,也不希望有一个不区分大小写特征的单独的字符串类,该类与我的所有其他字符串都不兼容。

所以我想出的是:

bool icasecmp(const string& l, const string& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](string::value_type l1, string::value_type r1)
                { return toupper(l1) == toupper(r1); });
}

bool icasecmp(const wstring& l, const wstring& r)
{
    return l.size() == r.size()
        && equal(l.cbegin(), l.cend(), r.cbegin(),
            [](wstring::value_type l1, wstring::value_type r1)
                { return towupper(l1) == towupper(r1); });
}

一个简单的函数,其中一个重载用于char,另一个重载用于whar_t。不使用任何非标准的东西,因此在任何平台上都可以。

相等性比较不会考虑诸如可变长度编码和Unicode规范化之类的问题,但是basic_string不支持我所知道的那种问题,并且这通常不是问题。

在需要对文本进行更复杂的词典处理的情况下,您只需要使用Boost这类第三方库即可。


2
如果将其作为模板并使用basic_string <T>而不是单独的字符串/ wstring版本,则可能可以实现该功能?
uliwitness 2014年

2
单个函数模板将如何调用toupper或towupper而不求助于使用专业化或宏,函数重载似乎比任何一种都更简单,更合适。
中微子2015年

9

简短又好。除了扩展的 std C lib ,没有其他依赖项。

strcasecmp(str1.c_str(), str2.c_str()) == 0

如果和相等,则返回true。 可能不存在,可能有类似物,等等。str1str2strcasecmpstricmpstrcmpi

示例代码:

#include <iostream>
#include <string>
#include <string.h> //For strcasecmp(). Also could be found in <mem.h>

using namespace std;

/// Simple wrapper
inline bool str_ignoreCase_cmp(std::string const& s1, std::string const& s2) {
    if(s1.length() != s2.length())
        return false;  // optimization since std::string holds length in variable.
    return strcasecmp(s1.c_str(), s2.c_str()) == 0;
}

/// Function object - comparator
struct StringCaseInsensetiveCompare {
    bool operator()(std::string const& s1, std::string const& s2) {
        if(s1.length() != s2.length())
            return false;  // optimization since std::string holds length in variable.
        return strcasecmp(s1.c_str(), s2.c_str()) == 0;
    }
    bool operator()(const char *s1, const char * s2){ 
        return strcasecmp(s1,s2)==0;
    }
};


/// Convert bool to string
inline char const* 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;
    return 0;
}

输出:

true
true
true
true
true

6
令人奇怪的是C ++的std :: string没有忽略-情况相比方法..
KYB

1
“ strcasecmp不是标准的一部分”-Mark Ransom 2014年12月1日19:57
Liviu

是的,但是大多数现代编译器都具有它或它的另一个类似物。stricmpstrcmpistrcasecmp,等谢谢。讯息已编辑。
kyb

TODO:使用cout << boolalpha而不是my,bool2str因为它隐式将bool转换为chars以进行流传输。
kyb

它在gcc的库中的<strings.h>中。
猫头鹰

7

可以通过使用c_str()和获取C字符串指针来完成不使用Boost的操作strcasecmp

std::string str1 ="aBcD";
std::string str2 = "AbCd";;
if (strcasecmp(str1.c_str(), str2.c_str()) == 0)
{
    //case insensitive equal 
}

6

假设您正在寻找一种方法而不是已经存在的魔术函数,坦率地说,没有更好的方法。我们都可以为有限的字符集编写带有巧妙技巧的代码片段,但是到了最后,您必须转换字符。

进行此转换的最佳方法是在比较之前进行转换。在编码方案方面,这给您提供了很大的灵活性,您的实际比较运算符应该忽略这些灵活性。

您当然可以将这种转换“隐藏”在自己的字符串函数或类的后面,但是在比较之前,您仍然需要转换字符串。


6

我写了一个不区分大小写的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>
    {
        static bool eq( const C& c1, const C& c2 )
        { 
            return ::toupper(c1) == ::toupper(c2); 
        }

        static bool lt( const C& c1, const C& c2 )
        { 
            return ::toupper(c1) < ::toupper(c2);
        }

        static int compare( const C* s1, const C* s2, size_t N )
        {
            return _strnicmp(s1, s2, N);
        }

        static const char* 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 ;
            }
            return 0 ;
        }

        static bool 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>
    {
        static bool eq( const wchar_t& c1, const wchar_t& c2 )
        { 
            return ::towupper(c1) == ::towupper(c2); 
        }

        static bool lt( const wchar_t& c1, const wchar_t& c2 )
        { 
            return ::towupper(c1) < ::towupper(c2);
        }

        static int compare( const wchar_t* s1, const wchar_t* s2, size_t N )
        {
            return _wcsnicmp(s1, s2, N);
        }

        static const wchar_t* find( const wchar_t* s, size_t N, const wchar_t& a )
        {
            for( size_t i=0 ; i<N ; ++i )
            {
                if( ::towupper(s[i]) == ::towupper(a) ) 
                    return s+i ;
            }
            return 0 ;
        }

        static bool 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;

1
这适用于常规字符,但不适用于所有Unicode,因为首字母大写不一定是双向的(希腊语中有一个很好的例子,涉及sigma,我现在不记得了;类似的东西有两个小写和一个大写) ,而且您都无法进行适当的比较)
coppro

1
这确实是错误的解决方法。区分大小写不应该是字符串本身的属性。当同一字符串对象需要区分大小写和不区分大小写的比较时,会发生什么?
Ferruccio

如果区分大小写不适合作为字符串的“一部分”,那么find()函数根本不适合。对您来说,这可能是对的,这很好。IMO关于C ++的最大优点是,它不会对程序员施加特定的范式。这就是您想要/需要的。
John Dibling

实际上,我认为大多数C ++专家(如标准委员会的专家)都同意将find()放在std :: basic_string <>中是错误的,同时也可以将很多其他内容放进去免费功能。此外,将其放入类型中还存在一些问题。
Andreas Magnusson,

正如其他人指出的那样,此解决方案有两个主要问题(具有讽刺意味的是,一个是接口,另一个是实现;-)。
康拉德·鲁道夫

4

我在使用Unicode库国际组件方面拥有丰富的经验-它们非常强大,并且提供了转换,语言环境支持,日期和时间渲染,大小写映射(您似乎不需要)以及排序规则的方法,其中包括区分大小写和不区分重音的比较(以及更多)。我只使用了C ++版本的库,但它们似乎也具有Java版本。

存在执行@Coincoin所指的规范化比较的方法,甚至可以考虑语言环境-例如(这是一个排序示例,并非严格相等),传统上在西班牙语(在西班牙)中,字母组合“ ll”在“ l”和“ m”,因此“ lz” <“ ll” <“ ma”。


4

strcmp()用于区分大小写和/ strcmpi()stricmp()不区分大小写的比较。两者都在头文件中<string.h>

格式:

int strcmp(const char*,const char*);    //for case sensitive
int strcmpi(const char*,const char*);   //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;

输出量

苹果和ApPlE相同

a先于b,所以苹果先于b


2
下注,因为这几乎不是C ++的处理方式。
Thomas Daugaard

这是我大学的c ++约定,但是在此处发布时我会记住它
reubenjohn 2013年

4
stricmp是Microsoft扩展AFAIK。BSD似乎有strcasecmp()代替。
uliwitness 2014年

3

聚会晚了,但这是使用的变体,std::locale因此可以正确处理土耳其语:

auto tolower = std::bind1st(
    std::mem_fun(
        &std::ctype<char>::tolower),
    &std::use_facet<std::ctype<char> >(
        std::locale()));

给您一个函子,该函子使用活动的语言环境将字符转换为小写,然后可以使用via std::transform生成小写的字符串:

std::string left = "fOo";
transform(left.begin(), left.end(), left.begin(), tolower);

这也适用于wchar_t基于字符串的字符串。


2

如果您最终选择了任何一种方法,请注意一下该方法是否恰好包括 strcmp某些答案表明:

strcmp通常不适用于Unicode数据。通常,它甚至不能与基于字节的Unicode编码(例如utf-8)一起使用,因为它strcmp只能进行逐字节比较,而以utf-8编码的Unicode代码点可以占用1个以上的字节。唯一能strcmp正确处理Unicode的情况是,当使用基于字节的编码编码的字符串仅包含U + 00FF以下的代码点时,则逐字节比较就足够了。


2

截至2013年初,由IBM维护的ICU项目是一个很好的答案。

http://site.icu-project.org/

ICU是“紧密跟踪行业标准的完整,可移植的Unicode库”。对于字符串比较的特定问题,Collat​​ion对象可以满足您的要求。

Mozilla项目于2012年中采用了ICU在Firefox中进行国际化;您可以在此处跟踪工程讨论,包括构建系统和数据文件大小的问题:


2

看起来上面的解决方案没有使用compare方法,而是再次实现了total,所以这是我的解决方案,希望它对您有用(工作正常)。

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
string tolow(string a)
{
    for(unsigned int i=0;i<a.length();i++)
    {
        a[i]=tolower(a[i]);
    }
    return a;
}
int main()
{
    string str1,str2;
    cin>>str1>>str2;
    int temp=tolow(str1).compare(tolow(str2));
    if(temp>0)
        cout<<1;
    else if(temp==0)
        cout<<0;
    else
        cout<<-1;
}

1

如果您不想使用Boost库,那么这里是仅使用C ++标准io标头的解决方案。

#include <iostream>

struct iequal
{
    bool operator()(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;
    }


    return 0;
}

我相信std :: toupper在#include <cctype>中,您可能需要包含它。
大卫·莱杰

如果您将使用这样的全局版本:: toupper,那么您可能不需要包含<ctype>,因为我猜有两个版本的c版本和具有语言环境的c ++版本。因此最好使用全局版本“ :: toupper()”
HaSeeB MiR

当其中一个字符串为空时,此解决方案将失败:“” –在这种情况下应返回false时返回true
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 2015年

馊主意。这是最糟糕的解决方案。
Behrouz.M 2015年

这不是一个好的解决方案,但是即使您要使用它,也需要在
宽字符串

如果有人可以解释为什么这是最糟糕的解决方案,那就太好了。因为性能问题?创建正则表达式很昂贵,但是之后的比较应该很快。
smibe 2015年

它既实用又可移植,主要问题是首先不能包含正则表达式使用的任何字符。因此,它不能用作一般字符串比较。它也会变慢,有一个标志可以使它按照smibe所说的那样工作,但仍然不能用作一般功能。
2016年

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.";

有关更多信息,参见:https : //msdn.microsoft.com/it-it/library/e0z9k731.aspx


除了此答案外,还值得阅读stackoverflow.com/a/12414441/95309,因为它是a)一个C函数,b)据说不是可移植的。
克劳斯·约根森

我们需要什么#include才能完成这项工作?
ekkis

1
@ekkis使用_stricmp你必须包括<string.h>的,你可以在这里阅读:docs.microsoft.com/en-us/cpp/c-runtime-library/reference/...
圣母院

-1
bool insensitive_c_compare(char A, char B){
  static char mid_c = ('Z' + 'a') / 2 + 'Z';
  static char up2lo = 'A' - 'a'; /// the offset between upper and lowers

  if ('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 2015年

这不支持非英语字符集。
罗伯特·安德鲁杰克

-3

比较仅由小写和大写字母组成的字符串的一种简单方法是进行ascii比较。ascii表中的所有大写和小写字母相差32位,使用此信息,我们可以得到以下信息:

    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
    }
}

3
据此,将发现“ ++ j”等于“ KKJ”,而发现“ 1234”等于“ QRST”。我怀疑那是任何人想要的东西。
celticminstrel 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.