# 介紹
string為C++中字串,很像 vector<char> 或 char arr[] 的加強版(之後會介紹vector)
雖然<iostream>函式庫中已經可以宣告string,但完整功能還是要引入<string>,如下:
```cpp=
#include <string>
```
## 宣告
宣告方式如下:
```cpp=
#include <iostream>
#include <string>
using namespace std;
int main(){
string a;
string b = "abcd123";
string c = "字串"; //需雙引號
}
```
## 輸入
### cin
```cpp=
#include <iostream>
#include <string>
using namespace std;
int main(){
string s;
cin >> s;
}
```
這樣輸入不會截取到空格
例如輸入
```
123 456 789
```
那麼s只會截取到123
即s=`123`
### getline
如果想截取包含空格的資訊(拿上方的例子即讓s=`123 456 789`)
則要使用getline
用法如下
如果getline前有cin,則需使用**cin.ignore()**(建議擺在cin正下方)
```cpp=
#include <iostream>
#include <string>
using namespace std;
int main(){
int n;
cin >> n;
cin.ignore();
string s;
getline(cin, s);
}
```
:::info
:::spoiler getline是什麼?
看他的字:get line,可以直接理解為抓取(get)一整行(line)
他的原形為
```cpp
getline(輸入流, 目的地, 停止字元)
```
輸入流基本上只會用到cin,目的地就是你要輸入給誰,停止字元就是他遇到誰會停,不打則為預設'\n'
例如
```cpp
string str;
getline(cin, str, 'c');
```
輸入`AaBbCcDd`時str=`AaBbC`
:::
:::info
:::spoiler cin.ignore是什麼?
cin.ignore的功能是忽略掉一些輸入
他的原形為
```cpp
cin.ignore(int a, char ch)
```
其中a代表最多忽略幾個、ch代表遇到哪個字元時停止(停止ignore,即繼續讀取),而這兩個條件只要一個成立就會結束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-based(從0開始)
```cpp=
#include <iostream>
#include <string>
using namespace std;
int main(){
string s = "0123456789";
cout << s[9] << '\n';
for(int i = 0; i < 10; i++)
cout << s[i] << ' ';
}
```
輸出結果如下
```cpp=
9
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=
#include <iostream>
#include <string>
using namespace std;
int main(){
string s = "asd", a = "jkl";
s += a;
cout << s; //輸出asdjkl
}
```
# 比較大小
兩個字串如果比較大小,會根據每個字母的ascii碼進行比較(圖:https://zh.wikipedia.org/zh-tw/ASCII)

使用十進位
例如
```cpp=
char c = 122;
cout << c; //輸出z
```
比較大小由兩字串第一個字開始比較
```cpp=
string f = "abcde";
string g = "abcd";
if(a > b)
cout << 1; //此行會執行
```
比較從f[0]與g[0]的ascii,因為兩者相等,所以比較f[1]與g[1];
f[1]與g[1]相等
f[2]與g[2]相等
f[3]與g[3]相等
在f[4]與g[4]時,f[4]為e(ascii碼為101),g[4]為'\0'(ascii碼為0)所以a>b回傳1
:::warning
:::spoiler **sort**
可以比較,也就可以sort
例如
```cpp=
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main() {
string arr[3]={"slhfd" , "dhf" , "sidf"};
sort(arr , arr+3);
for(int i=0 ; i<3 ; i++)
cout<< arr[i] << '\n';
}
```
輸出:
```cpp!
dhf
sidf
slhfd
```
:::
# 內建函式
- **.length() / .size()**
得字串大小
```cpp=
string a = "jfglk";
cout << a.size() << ' ' << a.length(); //輸出5 5
```
**.length()** 與 **.size()** 相同
- **to_string()**
將其他型態轉為string型態
```cpp=
int a = 5464;
string s = to_string(a) //s="5464"
```
- **stoi() / stod() / stoll() / stoull()**
將`string`轉為`int`/`double`/`long long`/`unsigned long long`型態
stoi=++s++tring ++to++ ++i++nt,以此類推,d=double, ll=long long, ull=unsigned long long
```cpp=
string a = "64645"
cout << stoi(a) - 645; //輸出64000;
```
:::warning
使用 **stoi() / stod() / stoll() / stoull()** 函式時,如果字串內有非數字之字元,會發生錯誤
如果字串內數字超過欲轉換型態之範圍,也會發生錯誤
:::
- **.find()**
如果找到該字元(串),則回傳最前面的位置(0-based),否則回傳string::npos
:::spoiler `string::npos`
呼叫`.find()`時的回傳值實際上不是`int`型態,而是一個叫`size_t`的資料型態,而`string::npos`代表`size_t`的最大值,代表不存在的位置(他是一個常數,由當前的位元系統決定,每台電腦不一定一樣)
:::
用法
str.find(目標字串)
str.find(目標字串,起始位置)
目標也可以是char或string變數
```cpp=
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(一個數)
int f = a.find("z");
cout << f << '\n'; //輸出-1,因為string::npos在int會自動溢位成-1
cout << a.find('d', 6) << '\n'; //輸出string::npos(一個數)
if(a.find('f') == string::npos)
cout << 1 << '\n'; //此行會執行
```
- **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()** 只能改變 **字元** (char型態)
:::
- **insert()**
**.insert(位置,字串)**
插入字串
```cpp=
string s = "asd";
string i = "56"
s.insert(0, i); //或s.insert(0,"56")
cout << s << '\n'; //輸出56asd
```
- **erase()**
**.erase(位置,數量)**
移除字串
```cpp=
string s = "456789";
s.erase(0, 3);
cout << s << '\n'; //從第0個開始往後刪除3個,輸出789
```
:::warning
注意:第一位都是0 (0-based)
:::
# 補充 stringstream
不太會用到
需引入函式庫<sstream>(沒有 `#include <stringstream>` )
```cpp=
#include <sstream>
```
需要搭配getline擷取空格
未來可搭配vector,直接push_back()即可
直接看範例
```cpp=
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
stringstream ss;
string s;
getline(cin, s);
int arr[1000], value, i = 0;
ss << s;
//亦可宣告時直接賦值:stringstream ss(s);
while(ss >> value) {
arr[i] = value;
i++;
}
for(int j = 0; j < i; j++)
cout << arr[j] << '\n';
}
```
:::warning
:::spoiler **vector版**(暫時不會沒關係)
```cpp=
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
int main() {
string s;
getline(cin, s);
stringstream ss;
ss << s;
int value;
vector<int> v;
while(ss >> value)
v.push_back(value);
for(int i = 0; i < v.size(); i++)
cout << v[i] << '\n';
}
```
:::
輸入
```cpp
123 456 789
```
輸出
```cpp
123
456
789
```