美文网首页Exceptional C++
【Exceptional C++(2)】不区分大小写的strin

【Exceptional C++(2)】不区分大小写的strin

作者: downdemo | 来源:发表于2018-01-26 13:06 被阅读24次

    问题

    • 写一个不分大小写的字符串比较类,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;
    

    相关文章

      网友评论

        本文标题:【Exceptional C++(2)】不区分大小写的strin

        本文链接:https://www.haomeiwen.com/subject/euwiaxtx.html