擴展C++ string類

在實際開發過程中,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;
}

輸出:




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章