- 除了順序容器共同的操作之外,string類型還提供了一些額外的操作。這些操作中 的大部分要么是提供string類和C 風格字符數組之間的相互轉換,要么是增加了允許我們用下標代替迭代器的版本。
- 標準庫string類型定義了大量函數。幸運的是,這些函數使用了重復的模式。由于 函數過多,本節初次閱讀可能令人心煩,因此讀者可能希望快速瀏覽本節。當你了解
string支持哪些類型的操作后,就可以在需要使用一個特定操作時回過頭來仔細閱讀
9 .5 .1 構造string的其他方法
- 除了我們在3.2.1節 (第76頁)已經介紹過的構造函數,以及與其他順序容器相同的構造函數(參見表9.3,第299頁)外,string類型還支持另外三個構造函數,如表9.11 所示。
- 這些構造函數接受一個string或一個const char*參數,還接受(可選的)指定拷貝多少個字符的參數。當我們傳遞給它們的是一個string時,還可以給定一個下標來指出從哪里開始拷貝:
const char *cp = "Hello World!!!"; //以空字符串結束的數組
char noNull[] = {'H','i'}; // 不是以空的字符串結束
string s1(cp); //拷貝cp中的字符直到遇到空的字符串 ,因此 s1 == "Hello World!!!"
string s2(noNull,2); //拷貝兩個字符串 s2 == "Hi"
string s3(noNull);//未定義 noNull不以空字符結束
string s4(cp + 6,5);//從cp[6]開始拷貝5個字符 s4 == "Word"
string s5(sl,6,5);//從s1[6]開始拷貝5個字符 s5 == "Word"
string s6(s1,6);//從s1[6]開始拷貝直至末尾 s6 == "Word"
string s7(s1,6,20);//從s1[6]開始拷貝直至末尾 s7 == "Word"
string s8(s1,16);//拋出一個out_of_range的異常
- 通常當我們從一個const char*創建string時,指針指向的數組必須以空字符結 尾,拷貝操作遇到空字符時停止。如果我們還傳遞給構造函數一個計數值,數組就不必以空字符結尾。如果我們未傳遞計數值且數組也未以空字符結尾,或者給定計數值大于數組大小,則構造函數的行為是未定義的。
- 當從一個string拷貝字符時,我們可以提供一個可選的開始位置和一個計數值。開始位置必須小于或等于給定的string的大小。如果位置大于size,則構造函數拋出一 個 out_of_range異常 (參見5.6節,第 173頁)。如果我們傳遞了一個計數值,則從給定位置開始拷貝這么多個字符。不管我們要求拷貝多少個字符,標準庫最多拷貝到string 結尾,不會更多。
substr操作
- substr操作 (參見表9.12) 返回一個string,它是原始string的一部分或全部的拷貝。可以傳遞給substr 一個可選的開始位置和計數值
- 如果開始位置超過了 string的大小,則 substr函數拋出一個out_of_range異常(參 見 5.6節,第 173頁)。如果開始位置加上計數值大于string的大小,則 substr會調 整計數值,只拷貝到string的末尾。
9.5.2改變string的其他方法
- string類型支持順序容器的賦值運算符以及assign、insert和erase操作(參見9.2.5節,第302頁;9.3.1節,第306頁;9.3.3節,第311頁)。除此之外,它還定義了額外的insert和erase版本。除了接受迭代器的insert和erase版本外,string還提供了接受下標的版本。下標指出了開始刪除的位置,或是insert到給定值之前的位置:
- s.insert(s.size(),5,'!');//在s末尾插入5個感嘆號
- s.erase(s.size()-5,5);//從s刪除最后5個字符
- 標準庫string類型還提供了接受C風格字符數組的insert和assign版本。例如,我們可以將以空字符結尾的字符數組insert到或assign給一個string:
- const char*cp="Stately,plumpBuck";
- s.assign(cp,7);//s=="Statelyn"
- s.insert(s.size(),cp+7);//s=="Stately,plumpBuck”
- 此處我們首先通過調用assign替換s的內容。我們賦予s的是從cp指向的地址開始的7個字符。要求賦值的字符數必須小于或等于cp指向的數組中的字符數(不包括結尾的空字符)。
- 接下來在s上調用insert,我們的意圖是將字符插入到s[size()]處(不存在的)元素之前的位置。在此例中,我們將cp開始的7個字符(至多到結尾空字符之前)拷貝到s中。
- 我們也可以指定將來自其他string或子字符串的字符插入到當前string中或賦予當前string:
- strings="some string",s2=nsome other string";s.insert(0,s2);//在s中位置0之前插入s2的拷貝
- //在s[0]之前插入s2中s2[0]開始的s2.size()個字符
- s.insert(0,s2,0,s2.size());
append和replace函數
- string類定義了兩個額外的成員函數:append和replace,這兩個函數可以改變string的內容。表9.13描述了這兩個函數的功能。append操作是在string末尾進行插入操作的一種簡寫形式:
- strings("C++Primer"),s2=s;//將s和s2初始化為"C++Primer*'
- s.insert(s.size(),"4thEd");//s=="C++Primer 4th Ed.
- s2.append("4thEd");//等價方法:將"4thEd."追加到s2;? s==s2
- replace操作是調用erase和insert的一種簡寫形式:
- //將“4th”替換為"5th"的等價方法
- s.erase(11,3);//s=="C++Primer Ed."
- s.insert(11,"5th");//s=="C++ Primer 5th Ed.”
- //從位置11開始,刪除3個字符并插入5th
- s2.replace(11,3,"5th");//等價方法:s==s2
- 此例中調用replace時,插入的文本恰好與刪除的文本一樣長。這不是必須的,可以插入一個更長或更短的string:
- s.replace(11,3,'Fifth');//s=="C++Primer Fifth Ed? ? 在此調用中,刪除了3個字符,但在其位置插入了5個新字符
改變string的多種重載函數
- 表9.13列出的append、assign,insert和replace函數有多個重載版本。根據我們如何指定要添加的字符和string中被替換的部分,這些函數的參數有不同版本。幸運的是,這些函數有共同的接口。
- assign和append函數無須指定要替換string中哪個部分:assign總是替換string中的所有內容,append總是將新字符追加到string末尾。replace函數提供了兩種指定刪除元素范圍的方式。可以通過一個位置和一個長度來指定范圍,也可以通過一個迭代器范圍來指定。insert函數允許我們用兩種方式指定插入點:用一個下標或一個迭代器。在兩種情況下,新元素都會插入到給定下標(或迭代器)之前的位置。
- 可以用好幾種方式來指定要添加到string中的字符。新字符可以來自于另一個string,來自于一個字符指針(指向的字符數組),來自于一個花括號包圍的字符列表,或者是一個字符和一個計數值。當字符來自于一個string或一個字符指針時,我們可以傳遞一個額外的參數來控制是拷貝部分還是全部字符。
- 并不是每個函數都支持所有形式的參數。例如,insert就不支持下標和初始化列表參數。類似的,如果我們希望用迭代器指定插入點,就不能用字符指針指定新字符的來源。
9.5.3string搜索操作
- string類提供了6個不同的搜索函數,每個函數都有4個重載版本。表9.14描述了這些搜索成員函數及其參數。每個搜索操作都返回一個string::size_type值,表示匹配發生位置的下標。如果搜索失敗,則返回一個名為string::npos的static成員(參見7.6節,第268頁)。標準庫將npos定義為一個conststring::size_type類型,并初始化為值-1。由于npos是一個unsigned類型,此初始值意味著npos等于任何string最大的可能大小(參見2.1.2節,第32頁)。
- find函數完成最簡單的搜索。它查找參數指定的字符串,若找到,則返回第一個匹配位置的下標,否則返回npos:
- string name("AnnaBelle");
- auto posl=name.find("Annan");//posl==0
- 這段程序返回0,即子字符串"Anna"在"AnnaBelle”中第一次出現的下標。搜索(以及其他string操作)是大小寫敏感的。當在string中查找子字符串時,要注意大小寫:
- string lowercase("annabelle**);
- posl=lowercase.find("Anna");//posl==npos
- 這段代碼會將posl置為npos,因為Anna與anna不匹配。
- 一個更復雜一些的問題是查找與給定字符串中任何一個字符匹配的位置。例如,下面代碼定位name中的第一個數字:
- string numbers("0123456789n"),name("r2d2");?
- autopos=name.find_first_of(numbers);//返回1,即,name中第一個數字的下標
- 如果是要搜索第一個不在參數中的字符,我們應該調用find_first_not_of。例如,為了搜索一個string中第一個非數字字符,可以這樣做:
- string dept("03714p3");
- autopos=dept.find_first_not_of(numbers);??//返回5--字符,p,的下標
指定在哪里開始搜索
- 我們可以傳遞給find操作一個可選的開始位置。這個可選的參數指出從哪個位置開 始進行搜索。默認情況下,此位置被置為0。一種常見的程序設計模式是用這個可選參數在字符串中循環地搜索子字符串出現的所有位置:
string::size_type pos = 0;
//每步循環查找name中的一個數
while((pos = name.find_first_of(numbers,pos))//numbers表示我們要找到的是數字!= string::npos)//npos是指string的末尾最后的位置,一般是std::container::size_typestd::cout << "found number at index" << pos << "element is "<< name[pos] << endl;++pos;//移動到下一個字符
}
- while的循環條件將pos重置為從pos開始遇到的第一個數字的下標。只要 find_first_of返回一個合法下標,我們就打印當前結果并遞增pos。 如果我們忽略了遞增pos,循環就永遠也不會終止。為了搞清楚原因,考慮如果不做遞增運算會發生什么。在第二步循環中,我們從pos指向的字符開始搜索。這個字符是—個數字,因此find_first_of會 (重 復 地 )返 回 pos!
逆向搜索
- 到現在為止,我們已經用過的find操作都是由左至右搜索。標準庫還提供了類似的, 但由右至左搜索的操作。rfind成員函數搜索最后一個匹配,即子字符串最靠右的出現位置:
- string river("Mississippi");
- auto first_pos = river. find ("is") ; // 返回 1
- auto last_pos = river. rfind (nisn) ; // 返回 4
- find返回下標1,表示第一個"is”的位置,而 rfind返回下標4,表示最后一個"is”的位置。
- 類似的,find_last函數的功能與find_first函數相似,只是它們返回最后一個而不是第一個匹配:
- find_last_of搜索與給定string中任何一個字符匹配的最后一個字符。
- find_last_not_of搜索最后一個不出現在給定string中的字符。
- 每個操作都接受一個可選的第二參數,可用來指出從什么位置開始搜索。
9.5.4compare函數
- 除了關系運算符外(參見3.2.2節,第79頁),標準庫string類型還提供了一組compare函數,這些函數與C標準庫的strcmp函數(參見3.5.4節,第109頁)很相似。類似strcmp,根據s是等于、大于還是小于參數指定的字符串,s.compare返回0、正數或負數。
- 如表9.15所示,compare有6個版本。根據我們是要比較兩個string還是一個string與一個字符數組,參數各有不同。在這兩種情況下,都可以比較整個或一部分字符串
9.5.5數值轉換
- 字符串中常常包含表示數值的字符。例如,我們用兩個字符的string表示數值15一字符1,后跟字符5。--般情況,一個數的字符表示不同于其數值。數值15如果保存為16位的short類型,則其二進制位模式為0000000000001111,而字符串"15"存為兩個Latin-1編碼的char,二進制位模式為0011000100110101。第一個字節表示字符1,其八進制值為061,第二個字節表示字符5,,其Latin-1編碼為八進制值065。
- 新標準引入了多個函數,可以實現數值數據與標準庫string之間的轉換:
- int i=42;string s=to_string(i);//將整數i轉換為字符表示形式
- doubled=stod(s);//將字符串s轉換為浮點數
- 此例中我們調用to_string將42轉換為其對應的string表示,然后調用stod將此string轉換為浮點值。
- 要轉換為數值的string中第一個非空白符必須是數值中可能出現的字符:
- string s2=“pi=3.14”;
- //轉換s中以數字開始的第一個子串,結果d=3.14
- d=stod(s2.substr(s2.find_first_of(*'+-.0123456789*')));
在這個stod調用中,我們調用了find_first_of(參見9.5.3節,第325頁)來獲得s中第一個可能是數值的一部分的字符的位置。我們將S中從此位置開始的子串傳遞給
stodostod函數讀取此參數,處理其中的字符,直至遇到不可能是數值的一部分的字符。然后它就將找到的這個數值的字符串表示形式轉換為對應的雙精度浮點值。 - string參數中第一個非空白符必須是符號(+或-)或數字。它可以以Ox或0X開頭來表示十六進制數。對那些將字符串轉換為浮點值的函數,string參數也可以以小數點(.)開頭,并可以包含e或E來表示指數部分。對于那些將字符串轉換為整型值的函數,根據基數不同,string參數可以包含字母字符,對應大于數字9的數。
?