【Exceptional C++(2)】不区分大小写的strin
2018-01-26 本文已影响24人
downdemo
问题
- 写一个不分大小写的字符串比较类,std::string提供了
operator==
实现比较,但是区分大小写。我们希望达到下面的目标
ci_string s("AbCdE");
assert(s == "abcde");
assert(s == "ABCDE");
assert(strcmp(s.c_str(), "AbCdE") == 0); // c_str()返回C字符串指针,const char* c_str()
assert(strcmp(s.c_str(), "abcde") != 0);
解答
- string头文件中可以看到
typedef basic_string<char> string;
- 所以string并不是一个真正的类,只是一个特化的typedef,再看basic_string<>模板声明
template<class charT,
class traits = char_traits<charT>,
class Allocator<charT> >
class basic_string;
- 所以string实际上是
basic_string<char, char_traits<char>, allocator<char> >
,先不关心allocator部分,关键的是char_traits部分,决定了字符的相互作用和比较运算。basic_string提供了常用的比较函数比较两个string对象是否相等或一个小于另一个。具体来说,char_traits模板提供了这些字符比较函数:eq() 相等, ne() 不等, lt() 小于, compare() 比较字符序列, find() 搜索字符序列
。如果希望在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 )
{
return memicmp(s1, s2, n); // 如果编译器没提供得自己实现
}
static const char* find( const char* s, int n, char a )
{
while( n-- > 0 && toupper(*s) != toupper(a))
{
++s;
}
return n >= 0 ? s : 0;
}
};
// 最后把它们合在一起
typedef basic_string<char, ci_char_traits> ci_string;
- 我们根本没碰basic_string就实现了不区分大小写的string,这揭示了basic_string模板的工作原理和实现使用上的灵活性,如果你不想用memicmp()和toupper(),可以用自己的代码替换这些比较函数
- ci_char_traits继承自char_traits<char>,但并非is-a关系,且两个类中所有函数都是static,也不存在多态
- 如果混用ci_string和string,比如相加,要定义ci_string自己的这些操作,或者取两者的.c_str()
- cout可以输出string,但不能输出ci_string
template<class char, class traits, class Allocator>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os,
const basic_string<charT, traits, Allocator>& str)
- 要输出ci_string,需要自己定义操作,或者直接使用.c_str()
ci_string s = "abc";
cout << s.c_str() << endl;