在c++中进行不区分大小写字符串比较而不将字符串转换为全大写或全小写的最佳方法是什么?
请指出这些方法是否对unicode友好,以及它们的可移植性如何。
在c++中进行不区分大小写字符串比较而不将字符串转换为全大写或全小写的最佳方法是什么?
请指出这些方法是否对unicode友好,以及它们的可移植性如何。
当前回答
比较只有小写字符和大写字符不同的字符串的一个简单方法是进行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
}
}
其他回答
如果是在POSIX系统上,可以使用strcasecmp。不过,这个函数不是标准C语言的一部分,在Windows上也不可用。这将对8位字符执行不区分大小写的比较,只要区域设置为POSIX。如果区域设置不是POSIX,则结果是未定义的(因此它可能进行本地化比较,也可能不进行)。没有宽字符的等效版本。
如果做不到这一点,大量历史上的C库实现都有stricmp()和strnicmp()函数。Windows上的Visual c++通过在它们前面加上下划线来重命名它们,因为它们不是ANSI标准的一部分,所以在那个系统中它们被称为_stricmp或_strnicmp。一些库可能还具有宽字符或多字节等效函数(通常命名为wcsicmp, mbcsicmp等)。
C和c++在很大程度上都不了解国际化问题,所以除了使用第三方库之外,这个问题没有好的解决方案。如果需要用于C/ c++的健壮库,请参阅IBM ICU (Unicode国际组件)。ICU适用于Windows和Unix系统。
我写了一个不区分大小写的char_traits版本,用于std::basic_string,以便在使用内置的std::basic_string成员函数进行比较、搜索等时生成一个不区分大小写的std::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;
无论你最终选择什么方法,如果该方法碰巧包含一些答案建议的strcmp的使用,请注意:
strcmp一般不处理Unicode数据。一般来说,它甚至不能使用基于字节的Unicode编码,比如utf-8,因为strcmp只进行逐字节的比较,而用utf-8编码的Unicode代码点可以占用超过1个字节。strcmp正确处理的唯一特定的Unicode情况是,使用基于字节的编码方式编码的字符串只包含低于U+00FF的代码点,那么每个字节的比较就足够了。
看到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;
}
Demo
比较只有小写字符和大写字符不同的字符串的一个简单方法是进行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
}
}