Exceptional C++, 实现一个不区分大小写的字符串比较类

时间:2022-02-25 00:57:58

C++标准库提供了字符串类std::string,这个类包含了字符串常用的操作,包括实现了operator==来实现字符串的比较,但这里的比较是区分大小写的。那么在不使用操作系统提供的不区分大小写函数的情况下,如何方便的利用std::string 来实现一个区分大小写的类呢?这里的奥妙就在于巧妙地运用了char_traits<char> 这个字符串的辅助模板类。
首先std::string 的定义如下:

typedef basic_string<char, char_traits<char>, allocator<char>> string

typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>> wstring

所以我们可以以char_traits<char>(这里仅讨论窄字符串)为基类,重新定义其中相关的字符比较函数,其它的不变,从而可以方便的实现不区分大小写的字符串类。

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

以上实现比较讨巧,但不得不说虽然这样可以实现,但还是会有几个问题,如下:
1. ci_char_traits 继承自char_traits<char>,但并不表示这两者之间是一种 is-a 关系,并且这两个类中的所有函数都是static 的,所以两者间也不存在多态的这种关系。
2. 当 ci_stringstring 去比较或者相加时会有问题,这个时候要么提供相应的比较或者相加函数,要么取两者的.c_str() 来取得内部的字符串指针。
3. 利用cout 来输出std::string 是支持的,因为c++标准库里有这样的定义:

template<class char, class traits, class Allocator>
basic_ostream<char, traits>&
operator<<(basic_ostream<char, traits>& os,
           const basic_string<char, traits, Allocator>& str)

cout 的类型则是basic_ostream<char, char_traits<char> > 所以 cout 是无法输出ci_string类型的,当然有一种比较简单的输出方式是用输出 .c_str() 的方式。