iniwf

风是温柔的,雨是伤心的,云是快乐的,月是多情的,爱是迷失的,恋是醉人的,情是难忘的,天是长久的,地是永恒的

编写一个STL 中的CString类

STL英文是Standard Template Library,也就是我们常说的C 标准模板库,。该标准库于1998年被正式纳入C 标准,给全世界的C 程序员带来了福音。最让我们兴奋的应该是它的跨平台性,使得你在WINDOW,UNIX ,Linux等操作系统上面用标准C 编写的程序不用修改即可移植。(当然要有C 的编译器)。


现在的编译器虽然对标准C 支持程度不同,单总体上还是很好。Windows平台的VC ,BC,Linux/UNIX平台的g 都是一流的编译器,都支持STL。而且STL是有源代码的,你可以扩展增加,避开这些微小的不同。

说到STL首先要说的当然是字符串处理类std::string,这可能是一个程序员使用最多的一个类,它的功能强大,使用非常方便。但习惯于用VC的CString开发的编程人员会感到有点不方便。幸运的是这个不方便可以很容易的解决,方法就是对标准的字符串类std::string进行包装,生成一个类似Cstring的类,我把它命名为Xstring。

下面就从Format函数说起,这可能是大部分人最希望用到的:

本函数是一个变参函数,对参数不定的函数其各式如下:

int Format(const char* pstrFormat, ... )

其中pstrFormat是格式串,三个点代表所有的参数。格式中的每个格式和后面的参数必须相对应,否则函数的执行会出现意想不到的结果;当然过多的参数将被忽略。格式分为简单字符和转换规范字符两类。具体格式规范有如下格式:

%[flags] [width] [.precision] [{h | l | I64 | L}]type

flags是标志字符,输出对齐,尾零,数值符号,进制数(八或十六)

width是宽度规范符,填补空格或0的个数

precision是精度规范符,打印字符最多个数,对于整数值,为最少数字个数

h短整型数的输出

I长整型数的输出

I64为64位的整型输出

如果你对格式还不清楚,请参考有关printf的格式资料。

对不定参数的处理也很特殊,要使用下面的几个函数

先声明一个变量va_list argList;

va_start(argList,pstrFormat);

int cnt =vsprintf(buff, pstrFormat, argList);

va_end(argList);

这样就把格式化后的结果保存在buff字符串中了。


然后最重要的就是计算这个buff有多大,如果大了就有内存浪费,小了完不成任务,所以要根据格式来动态计算,然后动态的开辟内存空间。就用一个循环来把格式串中的每一个字符读出来分别处理。先初始化一个长度变量nMaxLen =0;

for (const char * p = pstrFormat; *p != '0';p )

如果读出来的不是'%'或是‘%%'则长度加一。

if (*p != '%' || *( p) == '%')

{

nMaxLen = 1;

continue;

}

如果前一个字符是‘%',则读取格式,如果是‘#'则长度加2,来为‘0x'预留空间;如果是‘*',则读紧跟着的一个整数,得到指定的宽度;其他的‘+'、‘-'、‘ '、‘0'等字符主要是填充用,忽略长度。

for (; *p != '0'; p )

{

if (*p == '#')

nMaxLen = 2; // 处理 '0x'

else if (*p == '*')

nWidth = va_arg(argList, int); //如:'_' 中的5

else if (*p == '-' || *p == ' ' || *p == '0'|| *p == ' ')

; //忽略该符号

else // 不是标志字符就退出循环

break;

}

如果下一个字符是‘.'则忽略去读取其后面一个字符,如果是‘*'则也要读出其后的宽度,来计算精度。

if (*p == '*')

{

nPrecision = va_arg(argList, int);

p ;

}

else

{

nPrecision = atoi(p);

for (; *p != '0' && isdigit(*p); p )

;

}

接下来处理字符如果是‘h'、‘l'、‘I'、‘F'、‘N'等,则忽略计算长度。

如果读取字符是‘c'、‘C'则长度加上2(考虑宽字符的情况);如果读取的是‘s'、‘S'则要计算参数中给的字符串的宽度。

switch (*p)

{

case 'c':

case 'C':

nItemLen = 2;

va_arg(argList, char);

break;

case 's': // 字符串

case 'S':

nItemLen = strlen(va_arg(argList, const char*));

nItemLen = ((1) > (nItemLen)) ? (1) : (nItemLen);//如果是空串就使用1 即保存'0'

break;

}

如果读出的字符是‘d'、‘i'、‘u'、‘x'、‘o',‘e'、‘f'、‘G'、‘g'等,则长度加上对应的数值型的长度,当然最好使用sizeof计算,使得具有更好的移植能力。

case 'd':

case 'i':

case 'u':

case 'x':

case 'X':

case 'o':

va_arg(argList, int);

nItemLen = 32;

在for循环体的最后当然不要忘了把长度累计nMaxLen = nItemLen;当循环结束时,长度的计算也就完成了。

For循环结束时调用va_end(argList);

下面就可以开辟恰当的内存空间,来保存你的格式串。

char* ch = new char[nMaxLen 1];

有了空间再重新接收参数就可以了。

va_start(argList, pstrFormat);

vsprintf(ch, pstrFormat, argList);

va_end(argList);

最后不要忘了把空间加到std::string中,可以直接调用append函数:

this->append(ch);

然后释放你的内存空间

delete[] ch;


其他的函数可以用std::string中的相对应的功能包装即可,下面就再写一个MakeUpper函数,它也是CString中的。

void MakeUpper()

{

std::transform(this->begin (),

this->end (),this->begin (),

toupper);

}

是不是很容易呢,希望本文能起到抛砖引玉的作用,给你使用STL带来方便。

以上的程序编码在VC和g 中均可使用。本人曾用XString 类替代了一个用MFC编写的项目中的所有的CString类 ,使得它顺利的用G 编译通过。

/********************************************************************
** STL HEAH FILE USE FOR 徐岩柏
** Copyright(c) 2001 -2003
**-------------------------------------------------------------
Filename:     stl.h
Author    :    徐岩柏
Email        baikeley@hotmail.com        
Date:        2001-4-29
If you find any bug or you want to add some useful function 
please email to me.Redistribution and use in source are permitted
provided that: source distributions retain this entire copyright
notice and comment.
如果你在使用中发现BUG或添加了功能,请Email我。你可以使用与发布该文件
,但不得进行商业用途。你的发布要包含完整的本文件头。
********************************************************************
*/

#ifndef STL_H_BAIKELKEY
#define STL_H_BAIKELKEY
#pragma warning(disable:
4786
#pragma warning(disable:
4275
#include 
<iostream>
#include 
<Iterator>
#include 
<List>
#include 
<deque>
#include 
<map>
#include 
<numeric>     //accumulate
#include <set>
#include 
<stack>
#include 
<vector>
#include 
<algorithm>
#include 
<functional>
#include 
<string>
#include 
<fstream>
#include 
<memory>
#include 
<queue>
#include 
<complex>
//#include <sstream>
#include <cctype>   //isalpha()
#include <new>
#include 
<cstdarg>  //number not knowing arguments.such as :pringf
#include <utility>
#include 
<cstdio>
#include 
<cstdlib>
#include 
<cassert>

#define _min(a,b) ((a)<(b)?(a):(b))
#define _max(a,b) ((a)>(b)?(a):(b))
#define bzero(ptr,n) memset(ptr,0,n)
//////////以下是一个string的包装类/////////////////////
class XString : public std::string  
{    
public:
    
int Delete( int nIndex, int nCount = 1 )
    
{
        
this->erase(nIndex,nCount);
        
return this->GetLength();
    }

    
int Insert( int nIndex, const char * pstr )
    
{
        
this->insert(nIndex,pstr);
        
return this->GetLength();    
    }

    
int Insert( int nIndex, char ch )
    
{    
        XString strTmp(ch);
        
this->insert(nIndex,strTmp);
        strTmp.Empty();
        
return this->GetLength();
    }

    
int Remove( char ch )
    
{
        XString::iterator iter;
        
int count = 0;
        
for(iter = this->begin(); iter != this->end();iter ++)
        
{
            
if(*iter == ch)
            
{
                
this->erase(iter);count++;
            }

        }

        
return count;
    }

    
void MakeReverse( )
    
{
        XString strTmp;
        XString::iterator iter;
        iter
=this->end();
        iter
--;
        
for(; iter != this->begin(); iter--)
        
{
            strTmp 
+= *iter;
        }

        strTmp 
+= *iter;
        
*this = strTmp;
        strTmp.Empty();
    }

    
int Find( char ch ) const
    
{
        
return this->find(ch);
    }

    
int Find( const char * lpszSub ) const
    
{
        
return this->find(lpszSub);
    }

    
int Find( char ch, int nStart ) const
    
{
        
return this->find(ch,nStart);
    }

    
int Find( const char * pstr, int nStart ) const
    
{
        
return this->find(pstr,nStart);
    }

    
int ReverseFind( char ch ) const
    
{
        
return this->find_last_of(ch);    
    }

    
int FindOneOf( const char * lpszCharSet ) const
    
{
        
return this->find_first_of(lpszCharSet);
    }

    
int Format(const char* pstrFormat,  )
    
{///本函数仅仅支持ANSI标准字符集 '%[flags] [width] [.precision] [{h | l | I64 | L}]type'         
        assert(pstrFormat!=NULL);
        va_list argList;
        va_start(argList,pstrFormat); 
        
int nMaxLen = 0;
        
for (const char * p = pstrFormat; *!= '\0';p++ )
        
{
            
if (*!= '%' || *(++p) == '%')
            
{// 如果不是'%'就直接累计长度,如果是'%%'也使长度加1
                nMaxLen += 1;
                
continue;
            }

            
int nItemLen = 0//用来保存每个参数的长度
            int nWidth = 0//用来保存每一项的宽度
            for (; *!= '\0'; p ++)
            
{
                
if (*== '#')
                    nMaxLen 
+= 2;   // 处理 '0x'
                else if (*== '*')
                    nWidth 
= va_arg(argList, int);  //如:'%5f' 中的5
                else if (*== '-' || *== '+' || *== '0'|| *== ' ')
                    ;  
//忽略该符号
                else // 不是标志字符就退出循环
                    break;
            }

            
if (nWidth == 0)
            
//提取宽度
                nWidth = atoi(p);
                
for (; *!= '\0' && isdigit(*p); p ++)
                    ;
            }

            assert(nWidth 
>= 0);//有效宽度
            int nPrecision = 0//精度位数
            if (*== '.')
            
{
                p
++;// 跳过 '.'字符 (宽度.精度)            
                if (*== '*')
                
//有参数给出
                    nPrecision = va_arg(argList, int);
                    p 
++;// 取得精度,跳过字符
                }

                
else
                
//在格式串中有宽度
                    nPrecision = atoi(p);
                    
for (; *!= '\0' && isdigit(*p);    p ++)
                        ;
                }

                assert(nPrecision 
>= 0);//有效宽度
            }

            
switch (*p)
            
{
                
case 'h':     //short int 型
                    p ++;
                    
break;
                
case 'l':     //long double 型
                    p ++;
                    
break;
                
case 'F':     //近指针
                case 'N':    //远指针    
                case 'L':    //long double 型
                    p++;
                    
break;
            }

            
switch (*p)
            
{
                
case 'c':   //// 单个字符
                case 'C':
                    nItemLen 
= 2;
                    va_arg(argList, 
char);
                    
break;
                
case 's':    //// 字符串
                case 'S':
                    nItemLen 
= strlen(va_arg(argList, const char*));
                    nItemLen 
= ((1> (nItemLen)) ? (1) : (nItemLen);//如果是空串就使用1 即保存'\0'
                    break;
            }

            
if (nItemLen != 0)        
            
{
                nItemLen 
= ((nItemLen) > (nWidth)) ? (nItemLen) : (nWidth);//使用大者
                if (nPrecision != 0)
                    nItemLen 
= ((nItemLen) < (nPrecision)) ? (nItemLen) : (nPrecision);
            }

            
else
            
{
                
switch (*p)
                
{
                    
case 'd':    //整数的处理
                    case 'i':
                    
case 'u':
                    
case 'x':
                    
case 'X':
                    
case 'o':
                        va_arg(argList, 
int);
                        nItemLen 
= 32;  //四字节
                        nItemLen = ((nItemLen) > (nWidth+nPrecision)) ? (nItemLen) : (nWidth+nPrecision);//使用大者
                        break;
                    
case 'e':    //浮点数
                    case 'f':
                    
case 'g':
                    
case 'G':
                        va_arg(argList, 
double);
                        nItemLen 
= 32;//四字节
                        nItemLen = ((nItemLen) > (nWidth+nPrecision)) ? (nItemLen) : (nWidth+nPrecision);//使用大者;
                        break;
                    
case 'p':    //指针
                        va_arg(argList, void*);
                        nItemLen 
= 32;
                        nItemLen 
= ((nItemLen) > (nWidth+nPrecision)) ? (nItemLen) : (nWidth+nPrecision);//使用大者;
                        break;
                    
case 'n':
                        va_arg(argList, 
int*); //指向整数的指针,见BorlanderC++3.1库函数P352
                        break;
                    
default:
                        assert(
false);  //不能处理的格式,给出警告
                    }

                }

                nMaxLen 
+= nItemLen;//把该项的长度累计
            }

            va_end(argList);
            va_start(argList, pstrFormat);  
// 重新开始提取参数
            char* ch = new char[nMaxLen+1]; //分配内存
            vsprintf(ch, pstrFormat, argList);
            
//assert(vsprintf(ch, pstrFormat, argList) <= nMaxLen);
            this->append(ch); //加到string的尾部
            delete[] ch; //释放内存
            va_end(argList);
            
return nMaxLen;
    }

    
int GetLength() const
    
{
        
return this->length();
    }

    XString Left(
int nCount) const
    
{
        
if (nCount <=0
            
return XString("");    
        XString strTmp;
        strTmp 
= this->substr(0,nCount);
        
return strTmp;
    }

    XString Right(
int nCount) const
    
{
        
if (nCount <=0
            
return XString("");
        XString strTmp;
        
if (nCount > GetLength())
            strTmp 
= this->substr(0);
        
else
            strTmp 
= this->substr(GetLength()-nCount);
        
return strTmp;
    }

    XString Mid(
int nFirst) const
    
{
        XString strTmp;
        
if (nFirst >= GetLength())
            
return XString("");
        
if (nFirst <= 0)
            strTmp 
= this->substr(0);
        
else
            strTmp 
= this->substr(nFirst);
        
return strTmp;        
    }

    XString Mid( 
int nFirst, int nCount) const
    
{
        
if (nCount <= 0
            
return XString("");
        
if (nFirst >= GetLength())
            
return XString("");
        XString strTmp;
        
if (nFirst <= 0)
            strTmp 
= this->substr(0,nCount);
        
else
            strTmp 
= this->substr(nFirst,nCount);
        
return strTmp;                
    }

    XString
& operator=(const std::string str)
    
{
        
if (this->compare(str) == 0return *this;
        
this->assign(str);
        
return *this;
    }

    XString
& operator=(char ch)
    
{
        
this->Empty();
        
this->insert(this->begin(),ch);
        
return *this;
    }

    XString
& operator =const char * lpsz )
    
{
        
this->Empty();
        
this->append(lpsz);
        
return *this;
    }

    
void MakeUpper()
    
{
        std::transform(
this->begin (),
            
this->end (),this->begin (),
            toupper);
    }

    
void MakeLower()
    
{
        std::transform(
this->begin (),
            
this->end (),this->begin (),
            tolower);
    }

    
bool IsEmpty( ) const
    
{
        
return this->empty(); 
    }

    
void Empty( )
    
{//清除
        this->erase(this->begin(),this->end());
    }

    
char GetAt( int nIndex ) const
    
{
        
return this->at(nIndex);
    }

    
char operator []( int nIndex ) const
    
{
        
return this->at(nIndex);
    }

    
void SetAt( int nIndex, char ch )
    
{
        
this->at(nIndex) = ch;
    }

    
operator const char * ( ) const
    
{
        
return this->c_str();
    }

    friend XString 
operator + (const XString& string1, const XString& string2)
    
{
        XString str;
        str.append(string1);
        str.append(string2);
        
return str;
    }

    friend XString 
operator + ( const XString& string1, char ch )
    
{
        XString str;
        str.append(string1);
        str.insert(str.end(),ch);
        
return str;
    }

    friend XString 
operator + ( const XString& string1, char* ch )
    
{
        XString str;
        str.append(string1);
        str.append(ch);
        
return str;
    }

    
int Compare( const char * lpsz ) const
    
{
        XString str;
        str.append(lpsz);
        
return this->compare(str);
    }

    
int Compare( const XString& string1 ) const
    
{
        
return this->compare(string1);
    }

    
int CompareNoCase( const char * lpsz ) const
    
{
        XString str,strThis;
        str.append(lpsz);
        strThis 
= (*this);
        str.MakeLower();
        strThis.MakeLower();
        
return strThis.compare(str);
    }

    
int CompareNoCase( const XString& string1 ) const
    
{
        XString str,strThis;
        str 
= string1;
        strThis 
= (*this);
        str.MakeLower();
        strThis.MakeLower();
        
return strThis.compare(str);
    }

    
void TrimRight( )
    
{
        TrimRight (
' ');
    }

    
void TrimLeft( )
    
{   
        TrimLeft(
' ');
    }

    
void TrimLeft( char chTarget )
    
{
        std::
string::size_type pos;
        pos 
= this->find_first_not_of(chTarget);
        
if (pos == 0return
        
this->erase(this->begin(),this->begin()+pos);        
    }

    
void TrimRight( char chTarget )
    
{
        std::
string::size_type pos;
        pos 
= this->find_last_not_of(chTarget);
        
++pos;
        
if (pos == this->GetLength())
            
return
        
this->erase(this->begin()+pos,this->end());        
    }

    
void Replace( char chOld, char chNew )
    
{
        
for(int i=0;i<this->GetLength();i++)
        
{
            
if (this->at(i) == chOld)
                
this->at(i) = chNew;
        }
        
    }

    
void Replace(const char* chOld,const char* chNew )
    
{
        
int index = this->find(chOld);
        
while (index > -1)
        
{
            
this->erase(index,strlen(chOld));
            
this->insert(index,chNew);
            index 
= this->find(chOld);
        }

    }
        
    
char * GetBuffer( int nMinBufLength )
    
{
        
this->resize(nMinBufLength);
        
return this->begin();
    }

    
void ReleaseBuffer( int nNewLength = -1 )
    
{
        
this->TrimRight('\0');
    }

    XString(
const XString& string1)
    
{
        
this->append(string1);
    }

    XString(
const char *ch)
    
{
        
this->append(ch);
    }

    XString(
const char ch)
    
{
        
*this += ch;
    }

    XString()
    
{}
}
;
#endif

posted on 2009-03-16 23:20 iniwf 阅读(1359) 评论(3)  编辑 收藏 引用 所属分类: C&C++

评论

# re: 编写一个STL 中的CString类 2010-03-31 11:00 hpking

在vc2008不对,getBuffer  回复  更多评论   

# re: 编写一个STL 中的CString类[未登录] 2011-01-11 09:39 jack

Remove函数中删除容器元素用法不标准
改为:

int Remove( char ch )
{
XString::iterator iter;
int count = 0;
for(iter = this->begin(); iter != this->end();iter ++)
{
if(*iter == ch)
{
this->erase(iter++);count++;
continue;
}
++iter;
}
return count;
}

Format没有清空,如连续调用两次Format则内容出错。
  回复  更多评论   

# re: 编写一个STL 中的CString类[未登录] 2011-01-11 09:40 jack

@jack
for(iter = this->begin(); iter != this->end();iter ++)

这里写错,应是
for(iter = this->begin(); iter != this->end();)  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

常用链接

留言簿(2)

随笔分类

随笔档案

收藏夹

IT技术

积分与排名

最新评论

阅读排行榜

评论排行榜