# 簡介
`string` 很像 `char arr[]` 的加強版或`vector<char>`(之後會介紹),但其提供了更多方便使用的函數。

雖然`<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。
```

# 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)
###### 都看到這了難道不按個愛心支持一下嗎?