---
# System prepended metadata

title: 字串string
tags: [初階班]

---

# 介紹
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)
![](https://hackmd.io/_uploads/H1DBDFjY3.jpg)
使用十進位
例如
```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
```

