天天看點

STL學習(3)- string(2)以及stringstream

書接上文:STL學習(2)- string

詳細講一下string的其他用法,以及stringstream的用法。

append與replace

string s1 = s2 + s3;
           

上面這行代碼能夠運作是因為重載了+運算符,我們可以友善地拼接n個字元串并指派。append函數就是标準的在string末尾拼接string的函數。準确地說是在末尾追加字元串或者字元。但是單獨的+号隻能完成拼接,如果想要對拼接的字元串選擇一部分操作或者更多的功能,append函數能夠滿足大部分需求,而不需要先對拼接的字元串處理再拼接。下面是一些例子:

string s1 = "hello";
string s2 = "world";

s1.append(s2); // 就是s1 += s2,直接拼接
s1.append(s2,2,3); // s1後面拼接s2的子串,要求從下标為2開始的3個字元,即"rld"
s1.append("rua!",5); //在s1後拼接形參的前五個字元組成的子串
s1.append("rua!"); // 直接添加字元串
s3.append(233,'s');  // 在s3後面添加233個's'字元
           

replace,顧名思義是替換,先找再換。如果不使用replace,可以先利用疊代器與find函數找到位置,在進行字元串操作替換,非常麻煩。下面是一些用法:

string s1 = "hello";
string s2 = "world";

s1.replace(2,3,s2); // s1從下标9開始的5個字元被删除,同時在該位置插入s2,換而言之是下标9開始的5個字元換成了s2
s1.replace(1,3,s2,2,3); // s1從下标19開始的6個字元,被s2從下标7開始的6個字元替換
s1.replace(1,3,s2,3);  // s1從下标1開始的3個字元被s2的前3個字元替換。
s1.replace(1,2,"rua!"); // 同上,上面的額3種方法,s2均可直接換成字元串
s1.replace(2,3,3,'s'); // s1從下标2開始的3個字元被3個's'替換。
           

既然replace跟find有關,那麼就一定跟疊代有關了。我們利用下标來确定操作位置,同樣也可以用疊代器來操作,例如:

s1.replace(s1.begin()+2,s1.begin()+5,s2);
           

很簡單,就是把原來的下标表示換成利用beign與end傳回的指針值做錨,在記憶體上移動罷了。

compare

一般來說,我們想要比較2個字元串(字典順序),或者看兩個字元串是否相等,直接利用compare即可。其實compare還支援很多更精細的操作,例:

int ans = s1.compare(2,3,s2); // s1從下标2開始的3個字元與s2比較
int ans = s1.compare(2,3,s2,1,2); // s1從下标2開始的3個字元與s2從下标1開始的2個字元比較
// 同樣,參數可以直接填字元串例:
int ans = s1.compare(2,3,"rua!",1,2);
           

string與int、double等資料類型的轉換

一般來說,我們用itoa與atoi可以完成string與int的互相轉化,這個是相容C的一種做法。在VS上是會編譯錯誤,是以對于C++是不推薦使用這2個函數的。我們可以利用字元串流,也就是stringstream更加友善快捷地完成轉換操作。如果對itoa與atoi感興趣可以自行百度,部落客這裡就不多說了,下面會主要介紹一下stringstream

stringstream

顧名思義,字元串流。一般的C++程式都會加載頭檔案iostream,表示io流。這樣才能使用cin、cout等對象,友善快捷。stringstream跟iostream一樣,隻不過操作的對象由io(标準輸入輸出裝置等)變成了string。那麼我們也可以非常友善地對字元串進行處理,同時完成很重要的一個操作就是資料類型轉換。

首先我們要先聲明庫:

#include<sstream>
           

然後就可以聲明stringstream對象,利用<<與>>進行流操作。例:

stringstream ss;
string s1 = "hello world!";
string s2;

ss << s1;
ss >> s2;
           

這就是一個簡單的string流操作,s1輸入進流ss,在從流ss輸出到s2。

關于stringstream的建立,上面的代碼是常用的一種方法,另外還有一種直接初始化:

stringstream ss("rua!");
           

利用stringsteam進行資料類型轉換

簡單粗暴,将stirng或者其他資料類型輸入進流,輸出的時候輸出到其他的資料類型,即可完成轉換。

string str = "123";
stringstream ss;
ss << str;
int number;
ss >> number;
cout << number+1 << endl;
// ouput: 124
           

上面的代碼完成了将字元串轉換成為int類型。

int s = 123;
stringstream ss;
ss << s;
string str;
ss >> str;
cout << str + "dd" << endl;
// output: 123dd
           

上面的代碼完成了将int類型轉換為字元串。

想想我們在使用io流的時候,各種連續使用cout跟cin,沒有發生混亂的情況。stringstream也一樣,我們混着操作也完全可以,例如:

stringstream ss;
string s1 = "12 12.5 rua! string";
ss << s1;
int a;
double b;
string s2, s3;
ss >> a >> b >> s2 >> s3;
cout << a  << " " << b  << " " << s2  << " " << s3 << endl;
           

輸出跟想的一樣,流自動比對格式進行指派。

那麼我們搞一些壞事,對于競賽而言,完全不用考慮資料錯誤的情況,由于題目描述等,甚至第幾個資料是什麼資料類型都會明明白白寫出來。但是實際上項目中輸入的資料千奇百怪,那麼stringstream該如何處理?看下面的代碼:

stringstream ss;
string s1 = "12 12.5 rua! string";
ss << s1;
int a,b;
string s2, s3;
ss >> a >> b >> s2 >> s3;
cout << a  << " " << b  << " " << s2  << " " << s3 << endl;
           
// output: 12 12 .5 rua!
           

我們原來a跟b分别是int與double,而s1中也是一個int類型一個double類型。現在我們将b改成int類型,可以看到,12.5被分解了,讀取小數點的時候,由于比對的變量b是int類型,12指派給了b,而小數點之後的并沒有從流中消失,而是作為.12被字元串s2比對了。那麼s3就比對了"rua!",最後剩下子串" string"仍然在流中。

stringstream的清空

一般來說clear()函數是清空,但是實際上記憶體卻一直在增長。clear并不是完全清除緩存。是以我們需要重置這種操作。利用str方法來将緩存區重置為空的字元串(隻有一個'\0')。像這樣:

ss.str("");
           

這樣,我們将字元串流的流變成"",等于是空的了。而clear()實際上并不是清除流内容,而是清空了狀态。也就是說将流的狀态重置了,而内容仍然存在。