条款2:大小写不敏感的字符串--之一(1)
是否需要一个大小写不敏感(case-insensitive)的字符串类?如果乐意的话,你可以自己编写一个。
在本条款中包括以下三个相关的问题。
1."大小写不敏感"的含义是什么?
2.编写一个ci_string类,并且这个类的用法与标准库中std::string类一致。不同的是,ci_string对大小写不敏感,与通常提供的标准库扩展函数stricmp() 一样。ci_string应该可以像下面这样使用:
- ci_string s( "AbCdE" );
- // 大小写不敏感
- //
- assert( s == "abcde" );
- assert( s == "ABCDE" );
- // 当然,大小写将保持不变
- //
- assert( strcmp( s.c_str(), "AbCdE" ) == 0 );
- assert( strcmp( s.c_str(), "abcde" ) != 0 );
3.将大小写敏感作为对象的属性是否合适?
解答
上述三个问题的解答如下所示。
1."大小写不敏感"的含义是什么?
"大小写不敏感"的确切含义完全取决于你的应用程序和所使用的自然语言。例如,在许多自然语言中根本就没有大小写的概念。而对于那些支持大小写的自然语言,你可能还需要决定重音字符与非重音字符在比较时是否相等,以及其他一些诸如此类的情况。本条款所要解答的问题是:如何在标准的字符串上实现大小写不敏感性,而不考虑你所处的语言环境是什么。
2.编写一个ci_string类,并且这个类的用法与标准库中std::string类一致。不同的是,ci_string对大小写不敏感,与通常提供的标准库扩展函数stricmp()一样。
像"如何实现一个大小写不敏感的字符串类"这样的问题太常见了,我们甚至可以为其建立一个FAQ--因此就有了本条款。
以下是我们想要实现的功能:
- ci_string s( "AbCdE" );
- // 大小写不敏感
- //
- assert( s == "abcde" );
- assert( s == "ABCDE" );
- //当然,大小写将保持不变
- //
- assert( strcmp( s.c_str(), "AbCdE" ) == 0 );
- assert( strcmp( s.c_str(), "abcde" ) != 0 );
这里的关键之处在于:我们要理解在标准C++(www.cppentry.com)中,string类的底层表示是什么。如果查看string的头文件,将会看到下面这样的代码:- typedef basic_string<char> string;
从上面可以看到,string并不是一个类,它实际上是一个由模板生成的类型。然后,我们来看看下面模板basic_string<>的声明,其中也可以指定其他的模板特化参数:- template<class charT,
- class traits = char_traits<charT>,
- class Allocator = allocator<charT> >
- class basic_string;
因此,"string"的实际含义是"basic_string<char, char_traits<char>, allocator<char> >",在使用这个模板时也可以指定其他的模板特化参数。在这里无须关心allocator部分,重点在于char_traits部分,因为char_traits定义了字符之间的交互方式--包括字符的比较。
现在来对字符串进行比较。在basic_string模板类中提供了一些有用的比较函数,通过这些函数可以知道一个字符串是否等于、小于,或者大于另外一个字符串等等。这些字符串比较函数都是建立在char_traits模板提供的字符比较函数之上的。例如,在char_traits模板中提供了字符比较函数eq()和lt(),来比较两个字符是否相等,以及一个字符是否小于另一个,此外还提供compare()和find()这两个函数来对字符串进行比较和查找。
如果希望改变这些字符串比较函数的行为,那么就需要提供一个不同于char_traits的模板。以下是一种最简单的方法:
- struct ci_char_traits : public char_traits<char>
- // 对于不需要替换的函数,
- // 只需继承下来即可
- {
- static bool eq( 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 ); }
- // 如果你的系统支持memicmp函数,则可以直接使用;
- // 否则的话,要自行实现这个功能
- static const char*
- find( const char* s, int n, char a )
- {
- while( n-- > 0 && toupper(*s) != toupper(a) )
- {
- ++s;
- }
- return n >= 0 s : 0;
- }
- };