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; *p != '\0';p++ )
{
if (*p != '%' || *(++p) == '%')
{// 如果不是'%'就直接累计长度,如果是'%%'也使长度加1
nMaxLen += 1;
continue;
}
int nItemLen = 0; //用来保存每个参数的长度
int nWidth = 0; //用来保存每一项的宽度
for (; *p != '\0'; p ++)
{
if (*p == '#')
nMaxLen += 2; // 处理 '0x'
else if (*p == '*')
nWidth = va_arg(argList, int); //如:'%5f' 中的5
else if (*p == '-' || *p == '+' || *p == '0'|| *p == ' ')
; //忽略该符号
else // 不是标志字符就退出循环
break;
}
if (nWidth == 0)
{ //提取宽度
nWidth = atoi(p);
for (; *p != '\0' && isdigit(*p); p ++)
;
}
assert(nWidth >= 0);//有效宽度
int nPrecision = 0; //精度位数
if (*p == '.')
{
p++;// 跳过 '.'字符 (宽度.精度)
if (*p == '*')
{ //有参数给出
nPrecision = va_arg(argList, int);
p ++;// 取得精度,跳过字符
}
else
{ //在格式串中有宽度
nPrecision = atoi(p);
for (; *p != '\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) == 0) return *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 == 0) return;
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