3.vector實現字符串類
本章前言:
身爲土生土長的中國程序員,你肯定要用unicode來編寫程序。但是由wchar_t數組實現的字符串準確點說應該叫字符數組,但它在使用時比較繁瑣,而且容易出現數組越界和字符串結尾不爲0的錯誤。 爲了方便實現字符串相關的功能,DND引擎抽象了String類,其底層是vector<wchar_t>。爲什麼不使用std::string呢,因爲其不能定製化功能,例如+操作符直接連接兩個字符串、使用sprintf格式化生成字符串等等。
目標要點總結:
1. 實現字符串類
2. 類似基礎類型的使用方式
最終效果:
例如下面這樣使用:
Stringstr=String(L”Hello”)+ L” ” + L”DND!”;//str等於Hello DND!
具體的接口可以查看頭文件中的註釋。
class StrVector;
class DLL_APIString
{
public:
//==================構造、析構、操作符========================
String();//空串
String(constchar* str);//字符數組
String(constwchar_t* wcs);//寬字符數組
String(wchar_twc);//寬字符
~String();//析構
String(constString& b);//複製構造
//String(const unsigned b);
String(constint b);//數字構造
String(wchar_tch, unsigned len);//填充len個 ch
String(StrVector*);//strvector構造
String& operator=(constString& b);//=號重載
String operator+(constString& b) const;//連接
bool operator==(constString& b) const;//相同
bool operator<(constString& b) const;//小於
unsigned Get_Length() const;//返回長度
//==================轉化==================
const wchar_t*Get_Wcs() const;
void Get_Wide_Char_Str(wchar_t* target, unsigned max_len) const;//獲得寬字符數組
void Get_Multi_Byte_Str(char* target, unsigned max_len) const;//獲取字符數組
int Get_Int();//返回int
void Clear();//設爲空串
void Pop();//去掉結尾
//==================查找==================
unsigned Find_End(wchar_t wc);//查找最後一個
unsigned Find_Str(const String&str);//查找字符串位置,返回-1代表不存在
unsigned Find_N(wchar_t wc,unsigned N);//查找第n個要查找的字符
unsigned Get_Char_Count(wchar_t ch);//返回某字符出現的個數
String Get_Str(unsigned begin, unsigned end);//返回區間內的字符串
//==================刪除==================
void Cut(unsigned begin,unsigned end);//去掉區間內的字符串 [b, e]
void Cut_Tail(unsigned i);//去掉i位置後的包括i
void Cut_Head(unsigned i);//去掉i位置前的包括i
void Cut_Head_Str(const String& str);//去除頭部字符串
//==================修改==================
void Delete_Char(unsigned i);//i位置刪除一個字符
void Insert_Char(unsigned i, wchar_t ch);//i位置前插入一個字符,第一個字符位置爲0
void Replace_Char(wchar_t source, wchar_t target);//替換某個字符
unsigned Split(wchar_t wc,String* strs, unsigned max_size);//返回實際分隔後的字符串個數。例如 a;b;返回 a b 2
static StringFormat(unsignedmax_size, const wchar_t* format, ...);//max size不包含結束符
private:
StrVector* p;
void _init();
void _copy(const wchar_t*wcs);
};
前題簡要:
無。
具體實現:
由於需要生成動態鏈接庫,所以要在導出的接口中隱藏掉vector<wchar_t>類,可以使用void指針保存指向實際的vector<wchar_t>對象的地址,然後在接口定義中進行指針強轉。但這樣代碼看上去過於雜亂,有更好的方式實現。在前面的頭文件可以看到StrVector類的聲明:
class StrVector;
這樣就能在String類中聲明StrVector指針類型的變量p。在cpp中才實現了StrVector的定義,StrVector的定義如下:
class StrVector :public vector<wchar_t>
{
public:
StrVector(vector<wchar_t>*p) :
vector<wchar_t>(*p){}
StrVector(){}
};
這樣String類的指針p就能直接訪問基類vector<wchar_t>的成員。p指針的初始化交給String類的構造函數,構造函數會調用_init()。
void String::_init()
{
p = newStrVector;
}
例如默認構造函數會構造一個空串,如下:
String::String()
{
_init();
}
使用char字符數組構造:
String::String(constchar* str)
{
_init();//初始化
unsigned len =strlen(str) + 1;//字符串長度
wchar_t* wcs =new wchar_t[len];//分配臨時內存
//multi_byte轉wide_char(即char數組轉 wchar_t)
MultiByteToWideChar(CP_ACP,NULL, str, -1, wcs, len);
//設置vector最大長度爲len
p->reserve(len);
//複製字符串
_copy(wcs);
delete[] wcs;
}
其中首先獲取字符串長度,然後分配足夠的內存大小(加1放下結束符)。然後調用MultiByteToWideChar函數將char數組轉換至wchar_t數組,再預先設置vector<wchar_t>的最大長度。調用_copy將數據從buffer複製到vector,最後釋放buffer。
連接字符串的實現如下,首先複製構造一個臨時對象str,然後在尾部插入b字符的所有字符,最後再返回拷貝:
String String::operator+(constString& b) const
{
String str = *this;
str.p->insert(str.p->end(),b.p->begin(),b.p->end());
return str;
}
有很多系統函數、庫函數都要求以const wchar_t*類型作爲函數參數,讓String快速的返回字符串首地址很有必要。由於String的vector不包含結束符,所以需要擴容尾部爲0,但長度仍然不變。實際的實現如下:
const wchar_t*String::Get_Wcs()const
{
p->push_back(0);
wchar_t * temp = &(*p)[0];//保證0下標不越界
p->pop_back();
return temp;
}
比如在排序兩個字符串的時候就用到了Get_Wcs,如下:
bool String::operator<(constString& b) const
{
return wcscmp(Get_Wcs(),b.Get_Wcs()) < 0;
}
sprintf函數用來格式化字符串非常好用,所以有必要封裝類似的接口,封裝之後可以這樣生成一個字符串:
String str =String::Format(256,L"FPS:%d dt:%f", fps, dt);
Format是一個靜態變長參數函數,使用方式類似於sprintf,第一個256是指臨時buffer的最大長度,具體實現如下:
String String::Format(unsignedmax_size, const wchar_t* format, ...)
{
wchar_t* wcs =new wchar_t[max_size + 1];
va_list args;
va_start(args,format);
vswprintf_s(wcs,max_size + 1, format,args);
va_end(args);
String ret =String(wcs);
delete[] wcs;
return ret;
}
有關查找、刪除、編輯功能的實現這裏就不貼了,很簡單,使用vector的接口很好實現。作者以前實現的String是基於wchar_t數組的,由自己慢慢的添加接口而成(手動寫每個算法真的很麻煩)。最近規範下了命名,並換用了vector<wchar_t>實現,一天就完成了,所以標準庫還是好用啊!
作者:略遊
日期:17-06-20
QQ:1339484752