# 簡介 `string` 很像 `char arr[]` 的加強版或`vector<char>`(之後會介紹),但其提供了更多方便使用的函數。 ![](https://i.imgur.com/adgNy3W.png) 雖然`<iostream>`函式庫中可以宣告`string`,但<font color="#EB6E41">完整功能還是要引入名為</font> `<string>` <font color="#EB6E41">的標頭檔</font>。 ```cpp= #include <string> ``` # 宣告 ```cpp= string st1; //空字串。 string str2 = "Hello World"; // 把str2初始化為字串字面常數。 string str3("Hello World"); // 把str3初始化為字串字面常數。 string str4(str3); //把str4初始化為str3,str4為Hello World。 string str5(9, 'A'); //把str5初始為9個A,str5為AAAAAAAAA。 string str6(str2, 6, 2); //把str6初始化為str2的第6項往後2項(包含自身),str6為Wo。 ``` ::: warning 這樣宣告含有 10 個 str 的陣列,而不是大小為 10 的 str 字串。 ```cpp= string str[10]; ``` ::: --- # 輸入&輸出 ```cpp= #include <iostream> #include <string> using namespace std; int main(){ string s; cin >> s; } ``` 這樣輸入不會截取到空格,例如輸入 chrislai is god ,s 只會輸出 chrislai ,即 s = chrislai ,若想包含空格,可以用`getline()` 。 ## getline() ```cpp= getline(輸入流, 目的地, 停止字元) ``` 輸入流基本上只會用到`cin`,目的地是你要輸入給誰,停止字元就是他遇到誰會停,不打則為預設`'\n'` 。 ```cpp= string str; getline(cin, str, 'c'); ``` 輸入 AaBbCcDd 時,str= AaBbC 。 一般 cin 輸入如果遇到空格就會斷開,而 `getline()` 就可以連同空格一起擷取。 ```cpp= #include<iostream> #include<string> using namespace std; int main() { string str; getline(cin, str); cout << str << '\n'; } ``` 這樣輸入就會截取到空格,例如輸入 chrislai is god ,s 會輸出 chrislai is god ,即 s = chrislai is god。 :::warning 如果在使用 `getline(cin, str)` 之前使用 `cin`,`getline` 的輸入會取到上面 `cin` 裡緩存區的東西,所以要特別加上 `cin.ignore()` 讓 `getline` 釋放緩存區的東西。 </span> ```cpp= cin >> str; cin.ignore(); getline(cin, str); ``` ::: ## cin.ignore() 其功能是忽略掉一些輸入。 ```cpp= cin.ignore(int a, char c) ; ``` a 代表最多忽略幾個, c 代表遇到哪個字元時停止(停止 ignore,<font color="#EB6E41">即繼續讀取</font>),而這兩個條件只要一個成立就會結束 `igonre`。 ```cpp= string str; cin.ignore(3, 's'); cin >> str; ``` 輸入`abcd`時str=`d` ; 輸入`asdf`時str=`df` 。 其預設為`cin.ignore(1, EOF)`(EOF為End Of File),即忽略一個字元的輸入,放在`cin`下面的意義就是把cin完按的那個 enter 鍵(`'\n'`字元)忽略掉。 # 比較&修改 ## 判斷 可以使用一整個字串比較、修改。 ```cpp= #include <iostream> #include <string> using namespace std; int main(){ string a = "123",b = "123"; if(a == "123") cout << 1; //此行會執行。 if(a == b) cout << 1; //此行會執行。 } ``` ## 指定索引 跟陣列一樣,從`0`開始(0-based)。 ```cpp= #include <iostream> #include <string> using namespace std; int main(){ string s = "0123456789"; cout << s[9] << '\n'; //輸出 9。 for(int i = 0; i < 10; i++) cout << s[i] << ' '; //輸出 0 1 2 3 4 5 6 7 8 9。 } ``` 也陣列一樣,可進行比較或修改。 ```cpp= #include <iostream> #include <string> using namespace std; int main(){ string s = "0123456789"; s[8] = '0'; //將原本為數字8的位置變成0。 cout << s; //輸出0123456709。 if(s[9] == '9') cout << 1; //此行會執行。 } ``` :::warning 使用 [ ] 存取的結果為char型態,因此進行操作時必須使用單引號,否則可能會編譯錯誤。 ::: ## 加法 可以使用`+`或`+=`將想要的東西加在字串後方(沒有減、乘、除,更沒有取餘數),把字串接在一起,要注意順序,在左邊的會靠左。 ```cpp= string str1 = "Hello", str2 = "World"; cout << str1 + str2; //輸出HelloWorld。 ``` ## 大小關係 字串的比較會從左到右依照根據每個字元的ASCII碼逐一比較,直到符合以下任一情況。 * 兩個對應字元的 [ASCII碼](#ASCII碼) 不相等,則將其比較的結果做為字串間比較的結果。 * 找不到任何差異,但有一個字串的字元數比另一個字串還多,則較長的字串較大。 * 找不到任何差異,並且字串長度相同,則字串相等。 ```cpp= string str1 = "123", str2 = "12345"; string str3 = "123", str4 = "45"; cout << (str1 < str2); //輸出 1。 cout << (str1 == str3); //輸出 1。 cout << (str3 > str4); //輸出 0。 ``` # 內建函式 ## size() & length() 會回傳字串的長度。 ```cpp= string str = "HelloWorld"; cout << str.size() << ' ' << str.length(); //輸出10 10。 ``` 常搭配 for 迴圈,根據字串長度來決定執行次數。 ```cpp= string str; cin >> str; int n = str.length(); //n根據輸入的字串長度變化。 ``` ```cpp= string str = "HelloWorld"; for (int i = 0; i < str.size(); i++) cout << str[i] << ' '; //輸出H e l l o W o r l d 。 ``` :::info :::spoiler `.size()` 和 `.length` 的比較。 `.size()` 是為了兼容STL ( 標準樣板函式庫,之後會介紹 ) 的容器,而`.length` 是 C 語言的習慣而保留下來的,兩者原始碼相同,所以速度一致,也就是沒有差。 ::: ## find() 如果找到該字元(串),則回傳最前面的位置(`0-based`),否則回傳 `string::npos `。 ### string::npos `npos` 被定義為常數,但不是特定的某個值,而是代表 `string::size_type` ( 以下簡稱`size_t` ) 的最大值,也就是 `string` 的最後一個字元,但通常 `stirng` 不會塞滿,所以也用來表示不存在的字元。 ### string::size_type ( size_t ) 我們在使用 `string` 的函式時,他回傳值是由 `string` 函式庫所定義的`size_t`,對於 `size_t` 值域的定義為無符號 ( `unsigned` ),所以他不是任何整數型態,而是照當前位元系統來決定。 ```cpp= //在32位元系統中 str.find(目標字串,起始位置) string a = "abcdeee"; cout << a.find('a') << '\n'; //輸出0。 cout << a.find("cde") << '\n'; //輸出2。 cout << a.find("e") << '\n'; //輸出4。 cout << a.find("z") << '\n'; //輸出string::npos,在32位元系統下 size_t 最大值為 2^32 - 1。 int f = a.find("z"); cout << f << '\n'; //輸出-1,因為string::npos在int會自動溢位成-1。 cout << a.find('d', 6) << '\n'; //輸出string::npos(一個數)。 cout << (a.find('f') == string::npos) << '\n'; //輸出1,沒搜索到就回傳 string::npos。 cout << (str.find(" ") == -1) << '\n'; //輸出1,-1 的 size_t 會自動溢位成最大值。 int index = -1 ; cout << (str.find(" ") == index) << '\n'; //輸出0,兩者的型別與值皆不相同。 ``` ## to_string() 將其他型態轉化成字串型態。 ```cpp= int n = 114514; double d = 3.141; float f = 3.141; cout << to_string(n); //輸出114514。 cout << to_string(d); //輸出3.141000。 cout << to_string(f); //輸出3.141000。 ``` ## stoi() & stod() & stoll() & stoull() 將字串型態轉化成其他型態。 - stoi --> `int` 型態。 - stod --> `double`型態。 - stoll --> `long long`型態。 - stoull --> `unsigned long long`型態。 ```cpp= string a = "64645" ; cout << stoi(a) - 645; //輸出64000; ``` :::warning 使用 **stoi() / stod() / stoll() / stoull()** 函式時,如果字串內有非數字之字元,會發生錯誤。 如果字串內數字超過欲轉換型態之範圍,也會發生錯誤。 ::: ## toupper() & tolower() 將該字元轉為大寫或小寫(若非英文字母則相同)。 ```cpp= string a = "Aa.Bb.Cc"; for(int i = 0; i < a.length(); i++){ a[i] = tolower(a[i]); } cout << a << '\n'; //輸出aa.bb.cc。 for(int i = 0; i < a.length(); i++){ a[i] = toupper(a[i]); } cout << a << '\n'; //輸出AA.BB.CC。 ``` ::: warning `toupper()` 和 `tolower()` 只能改變字元型態。 ::: ## insert() & erase() 插入字串。 ```cpp= s.insert(位置,字串) string s = "asd"; string i = "56" s.insert(0, i); //也可寫成s.insert(0,"56")。 cout << s << '\n'; //輸出56asd。 ``` 移除字串。 ```cpp= s.erase(位置,數量) string s = "456789"; s.erase(0, 3); cout << s << '\n'; //從第0個開始往後刪除3個,輸出789。 ``` # ASCII碼 [ASCII碼](https://zh.wikipedia.org/zh-hk/ASCII)(發音: /ˈæski/,American Standard Code for Information Interchange,美國標準資訊交換碼)是目前世界上使用最廣泛的字元編碼,即用數字來表示字元,也可以互相轉換。 ```cpp= string str = "ABC"; cout << str[0] - 'A' << '\n'; //輸出0。 cout << str[1] - 'A' << '\n'; //輸出1。 cout << str[2] - 'A' << '\n'; //輸出2。 ``` ```cpp= char chr = 'A'; cout << char(65); //輸出A。 cout << int('A'); //輸出65。 cout << int(chr); //輸出65。 ``` ![image](https://hackmd.io/_uploads/rJe-aP2TTR.png) # StringStream 需要引入標頭檔。 ```cpp= #include <sstream> ``` `StringStream` 像是數字與字串中間的橋梁,同時也是類似於 `cin` 的輸入流,所以當測資是一長串無法確定筆數時可以用 `StringStream` 配合 `getline` 切分。 ```cpp= string str = "ABC123"; stringstream ss; stringstream ss(str); //其值為ABC123。 ``` ## 輸入&輸出 ```cpp= #include<iostream> #include<string> #include<sstream> using namespace std; int main () { stringstream ss; int n = 114514; string str; ss << n; ss >> str; cout << str; //輸出114514。 } ``` 這表示其可以將 `int` 轉換成 `string` 型態,反之亦然,但還是較常用前面介紹的函式。 ## 初始化 因為 `sstream` 重複宣告很消耗時間與記憶體,但已經寫入的 `sstream` 不能直接使用,必須經過初始化。 ```cpp= ss.str(""); ss.clear(); ``` <font color="#EB6E41">兩行都要打</font>。 若沒有打 `s.str("")`,`sstream` 結尾的 `EOF` 不會被清除。 若沒有打 `ss.clear()` 雖然可以正常輸入輸出,但原先的字串還是會保留在 `sstream` 中,造成記憶體的消耗。 ## getline() 用 stringstream 切分 ```cpp= #include<iostream> #include<string> #include<sstream> using namespace std; int main () { string str; getline(cin, str); stringstream ss(str); //直接宣告含有str字串的sstream。 while (getline(ss, str, ' ')) { //當遇到空格時停止擷取。 cout << str << endl; } } ``` 這樣可以把輸入存取到陣列裡或 `Vector` (之後會介紹) 裡面。 ## 換行擷取 因為換行字符對該函數來說是有效輸入,因此在擷取時會遇到擷取空字串的狀況。 ```cpp= #include<iostream> #include<string> #include<sstream> using namespace std; int main () { int n; cin >> n; while (n--) { string str; getline(cin, str); cout << str << '\n'; } } ``` 輸入 ```cpp= abc def geh ``` 輸出 ```cpp= abc def ``` 為了解決此問題,可以藉由判斷來解決問題。 ```cpp= #include<iostream> #include<string> #include<sstream> using namespace std; int main () { int n; cin >> n; while (n--) { string str; while (str.length() == 0) getline(cin, str); cout << str << '\n'; } } ``` 輸入 ```cpp= abc def geh ``` 輸出 ```cpp= abc def geh ``` # 例題 ###### 有什麼題目沒提到或有新增的煩請留言告知。 [a003: 提款卡密碼](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a003) [a010: 聖經密碼](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a010) [a012. Johnny B. Goode](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a012) [a013: You can say that again!](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a013) [a102: 字串操作練習](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a102) [a168: 箱子裡面是什麼](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a168) [a188: 數字翻轉](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a188) [a199: 文字獄(一)](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a199) [a202: 文字獄(二)](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a202) [a205: 文字獄(三)](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a205) [a228: pJ Count! Count! Count!](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a228) [a233: 西元年轉天干地支年](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a233) [a240: 秘密差 (APCS 106/03/04)](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a240) [a241: 2019 Forbes](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a241) [a247: pE 幾的"被"數?](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a247) [a251: 多元選修好難喔](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a251) [a261: Neko我婆#ΦωΦ](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a261) [a423: 光頭學英文](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a423) [a450: 成為數學genius](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a450) [a467: 二則運算](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a467) [a533: pC Sentence Compressor](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a533) [a578: 文字獄(四)](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a578) [a711: ahoy!! 我想要警告](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a711) [a747: 都不揪](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a747) [a832: 蘿莉圖真香](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a832) [a872: 神奇的字串(2): 強迫症辛苦Coding日常](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a872) [a877: 迴文針](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a877) [a878: 好想海底撈____________________________月](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a878) [a892: 用Code寫Code?](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=a892) - [b166: 改作文](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=b166) - [b172: 等式(1)](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=b172) - [b174: 等式(2)](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=b174) - [b183: 密碼](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=b183) - [b184: 我的字典沒有困難!!!](https://dandanjudge.fdhs.tyc.edu.tw/ShowProblem?problemid=b184) ###### 都看到這了難道不按個愛心支持一下嗎?