在实际开发过程中,C++string类使用起来有很多不方便的地方,笔者根据根据这些不足简单的扩展了这个类,如增加与数字之间的相互转化和格式化字符串。不足的地方望指正。读者也可以根据自己需求继续扩展。
头文件:exstring.h
/* Author: wuqiang Email: [email protected] Description:exstring is a subclass of basic_string.It is added some userful operations,such as toUpper,toLower,toNumber,fromNumber,format,etc.It can also convert between basic_string seamlessly,which is very important for compatibility. And it is almostly a wrapper of some C++ standard library,so there should be no bugs. If you find some,please let me known.It is totally free,you can use it in any way you desire. */ #pragma once #include <string> #include <stdarg.h> #include <algorithm> #include <sstream> #include <iomanip> using namespace std; #ifndef INLINE #define INLINE inline #endif //INLINE static ios_base::fmtflags BaseFlag(int base) { return (base == 16) ? (ios_base::hex) : ( (base == 8) ? (ios_base::oct) : (ios_base::dec) ); } template<class _Elem> struct ex_char_traits { }; template<> struct ex_char_traits<char> { static INLINE int ct_vscprintf(const char* format, va_list argptr ) { return _vscprintf(format, argptr); } static INLINE int ct_vstprintf_s(char* buffer, size_t numberOfElements, const char* format, va_list argptr) { return vsprintf_s(buffer, numberOfElements, format, argptr); } }; template<> struct ex_char_traits<wchar_t> { static INLINE int ct_vscprintf(const wchar_t* format, va_list argptr ) { return _vscwprintf(format, argptr); } static INLINE int ct_vstprintf_s(wchar_t* buffer, size_t numberOfElements, const wchar_t* format, va_list argptr) { return vswprintf_s(buffer, numberOfElements, format, argptr); } }; template<class _Elem, class _Traits, class _Ax, class Type> Type ConvertToNumber(basic_stringstream<_Elem, _Traits, _Ax>& ss, Type t, int base) { ss.setf(BaseFlag(base), ios_base::basefield); ss >> t; return t; } template<class _Elem, class _Traits, class _Ax> float ConvertToNumber(basic_stringstream<_Elem, _Traits, _Ax>& ss, float t, int/*ignore base*/) { ss >> t; return t; } template<class _Elem, class _Traits, class _Ax> double ConvertToNumber(basic_stringstream<_Elem, _Traits, _Ax>& ss, double t, int/*ignore base*/) { ss >> t; return t; } template<class _Elem, class _Traits, class _Ax, class _ExTraits> class basic_exstring : public basic_string<_Elem, _Traits, _Ax> { public: typedef basic_exstring<_Elem, _Traits, _Ax, _ExTraits> _Myt; typedef basic_string<_Elem, _Traits, _Ax> _Mybase; #pragma region "constructor" //所有构造函数的行为同basic_string explicit INLINE _Myt(const _Ax& al = _Ax()) :_Mybase(al) { } INLINE _Myt(const _Myt& rhs) :_Mybase(rhs) { } INLINE _Myt(const _Myt& rhs, size_type pos, size_type n,const _Ax& al = _Ax()) :_Mybase(rhs, pos, n, al) { } INLINE _Myt(const _Elem *s, size_type n, const _Ax& al = _Ax()) :_Mybase(s, n, al) { } INLINE _Myt(const _Elem *s, const _Ax& al = _Ax()) :_Mybase(s, al) { } INLINE _Myt(size_type n, _Elem c, const _Ax& al = _Ax()) :_Mybase(n, c, al) { } INLINE _Myt(const_iterator first, const_iterator last,const _Ax& al = _Ax()) :_Mybase(first, last, al) { } //string(wstring)转化为exstring(exwstring) INLINE _Myt(const _Mybase& base) :_Mybase(base) { } #pragma endregion //constructor #pragma region "general operation" //所有字符转为大写,改变自身 _Myt& toUpper() { transform(begin(), end(), begin(), toupper); return *this; } //所有字符转为大写,不改变自身 _Myt toUpper() const { _Myt s; transform(begin(), end(), s.begin(), toupper); return s; } //所有字符转为小写,改变自身 _Myt& toLower() { transform(begin(), end(), begin(), tolower); return *this; } //所有字符转为大写,不改变自身 _Myt toLower() const { _Myt s(_Mysize, _Elem()); transform(begin(), end(), s.begin(), tolower); return s; } //将所有oldStr替换为newStr _Myt& replace(const _Myt& oldStr, const _Myt& newStr) { if (oldStr.empty()) return *this; size_type index; while ( (index = find(oldStr)) != npos ) _Mybase::replace(index, oldStr.size(), newStr); return *this; } //删除左边所有包含在target中的字符 _Myt& trimLeft(const _Myt& target) { while (!empty() && (target.find(*begin()) != npos)) erase(begin()); return *this; } //删除右边所有包含在target中的字符 _Myt& trimRight(const _Myt& target) { while (!empty() && target.find(*rbegin()) != npos) erase(--end()); return *this; } //返回左边count个字符,count大于总长度则返回整个字符串 _Myt left(size_type count) const { return substr( 0, count ); } //返回右边count个字符,count大于总长度则返回整个字符串 _Myt right(size_type count) const { return substr( _Mysize < count ? 0 : _Mysize - count ); } //忽略大小写判断两个字符串是否相等 int compareNoCase(const _Myt& rhs) const { return toLower().compare(rhs.toLower()); } //判断字符串是否以制定字符串开头 bool beginWith(const _Myt& rhs) const { return find(rhs) == size_type(0); } //判断字符串是否以制定字符串结尾 bool endWith(const _Myt& rhs) const { if(rhs.size() > _Mysize) return false; return compare(_Mysize - rhs.size(), rhs.size(), rhs) == 0; } #pragma endregion //general operation #pragma region "convert between numbers" //将字符串转为数字 //base:进制数。可以为8,10,16,如果其它值则强制为10。浮点数则忽略此参数 template<typename T> T toNumber (int base = 10) const { T t = T(); basic_stringstream<_Elem, _Traits, _Ax> ss(_Myptr()); return ConvertToNumber<_Elem, _Traits, _Ax>(ss, t, base); } //将整数转化为字符串 //base:进制数。可以为8,10,16,如果其它值则强制为10 template<typename T> static _Myt fromNumber ( T number, int base = 10 ) { basic_stringstream<_Elem, _Traits, _Ax> ss; ss.setf(BaseFlag(base), ios_base::basefield); ss << number; return ss.str(); } //将float转化为字符串 //f:格式化参数。可以为'f','e','E','g','G'。'f'为定点数,'e'或'E'表示科学计数法 // 'g'或‘G’表示格式化为定点数或科学计数法,看哪一个表示方便。 //prec:小数点后的位数(定点数表示法)或总的有效位数(科学计数法) static _Myt fromNumber ( float number, _Elem f = _Elem('g'), int prec = 6 ) { return fromNumber(static_cast<double>(number), f, prec); } //将double转化为字符串,参数解释同上 static _Myt fromNumber ( double number, _Elem f = _Elem('g'), int prec = 6 ) { basic_stringstream<_Elem, _Traits, _Ax> ss; ss << setprecision(prec); if ( _Traits::eq(f, _Elem('f')) ) ss << setiosflags(ios_base::fixed); else if ( _Traits::eq(f, _Elem('e')) || _Traits::eq(f, _Elem('E')) ) ss << setiosflags(ios_base::scientific); ss << number; return ss.str(); } #pragma endregion //convert between numbers #pragma region "format string" //将szFormat格式化为字符串,参数解释同sprintf void format(const _Elem* szFormat, ...) { if(!szFormat) return; va_list argList; va_start(argList, szFormat); formatV(szFormat, argList); va_end(argList); } //将szFormat格式化为字符串,参数解释同sprintf void formatV(const _Elem* szFormat, va_list argList) { if(!szFormat) return; int nLength = _ExTraits::ct_vscprintf(szFormat, argList); if(nLength < 0) return; resize(nLength); _ExTraits::ct_vstprintf_s(_Myptr(), nLength + 1, szFormat, argList); va_end(argList); } #pragma endregion //format string }; typedef basic_exstring<char, char_traits<char>, allocator<char>, ex_char_traits<char> > exstring; typedef basic_exstring<wchar_t, char_traits<wchar_t>, allocator<wchar_t>, ex_char_traits<wchar_t> > exwstring;
#include <iostream> #include <tchar.h> #include "exstring.h" #ifdef _UNICODE typedef exwstring tstring; #define tcout wcout #else typedef exstring tstring; #define tcout cout #endif //_UNICODE int main(int argc, char* argv[]) { tstring s(_T("\t Hello ExString\r\n")); tcout << _T("result of triming left:") << s.trimLeft(_T("\t ")) << endl; tcout << _T("result of triming right:") << s.trimRight(_T("\r\n")) << endl; tcout << _T("result of compare") << s.compareNoCase(_T("hello exstring")) << endl; tcout << _T("result of converting to upper:") << s.toUpper() << endl; tcout << _T("result of converting to lower:") << s.toLower() << endl; tcout << _T("the left 5 chars:") << s.left(5) << endl; tcout << _T("the right 8 chars:") << s.right(8) << endl; tcout << _T("result of appending:") << s.append(_T(",exstring is practical")) << endl; tcout << _T("result of replacing:") << s.replace(_T("exstring"), _T("Exstring")) << endl; s.format(_T("sizeof(%s) is %d(0x%x)"), _T("exstring"), sizeof(exstring), sizeof(exstring)); tcout << _T("result of formating:") << s << endl; tcout << tstring(_T("0xFF")).toNumber<int>(16) << endl; tcout << tstring(_T("-1")).toNumber<unsigned __int64>() << endl; tcout << tstring(_T("12.3456789")).toNumber<float>() << endl; tcout << tstring::fromNumber(255) << endl; tcout << _T("0x") << tstring::fromNumber(__int64(-1), 16).toUpper() << endl; tcout << tstring::fromNumber(12.3456789, _T('f'), 4) << endl; tcout << tstring::fromNumber(12.3456789, _T('E'), 4) << endl; return 0; }
输出: