跳转至

string

string 是什麼

std::string 是在標準庫 <string>(注意不是 C 語言中的 <string.h> 庫)中提供的一個類,本質上是 std::basic_string<char> 的別稱。

為什麼要使用 string

在 C 語言中,提供了字符串的操作,但只能通過字符數組的方式來實現字符串。而 string 則是一個簡單的類,使用簡單,在 OI 競賽中被廣泛使用。並且相較於其他 STL 容器,string 的常數可以算是非常優秀的,基本與字符數組不相上下。

string 可以動態分配空間

和許多 STL 容器相同,string 能動態分配空間,這使得我們可以直接使用 std::cin 來輸入,但其速度則同樣較慢。這一點也同樣讓我們不必為內存而煩惱。

string 重載了加法運算符和比較運算符

string 的加法運算符可以直接拼接兩個字符串或一個字符串和一個字符。和 std::vector 類似,string 重載了比較運算符,同樣是按字典序比較的,所以我們可以直接調用 std::sort 對若干字符串進行排序。

使用方法

下面介紹 string 的基本操作,具體可看 C++ 文檔

聲明

1
std::string s;

轉 char 數組

在 C 語言裏,也有很多字符串的函數,但是它們的參數都是 char 指針類型的,為了方便使用,string 有兩個成員函數能夠將自己轉換為 char 指針——data()/c_str()(它們幾乎是一樣的,但最好使用 c_str(),因為 c_str() 保證末尾有空字符,而 data() 則不保證),如:

1
2
3
printf("%s", s);          // 編譯錯誤
printf("%s", s.data());   // 編譯通過,但是是 undefined behavior
printf("%s", s.c_str());  // 一定能夠正確輸出

獲取長度

很多函數都可以返回 string 的長度:

1
2
3
printf("s 的長度為 %lu", s.size());
printf("s 的長度為 %lu", s.length());
printf("s 的長度為 %lu", strlen(s.c_str()));
這些函數的複雜度

strlen() 的複雜度一定是與字符串長度線性相關的。

size()length() 的複雜度在 C++98 中沒有指定,在 C++11 中被指定為常數複雜度。但在常見的編譯器上,即便是 C++98,這兩個函數的複雜度也是常數。

Warning

這三個函數(以及下面將要提到的 find 函數)的返回值類型都是 size_tunsigned long)。因此,這些返回值不支持直接與負數比較或運算,建議在需要時進行強制轉換。

尋找某字符(串)第一次出現的位置

find(str,pos) 函數可以用來查找字符串中一個字符/字符串在 pos(含)之後第一次出現的位置(若不傳參給 pos 則默認為 0)。如果沒有出現,則返回 string::npos(被定義為 -1,但類型仍為 size_t/unsigned long)。

示例:

1
2
3
4
5
6
7
string s = "OI Wiki", t = "OI", u = "i";
int pos = 5;
printf("字符 I 在 s 的 %lu 位置第一次出現\n", s.find('I'));
printf("字符 a 在 s 的 %lu 位置第一次出現\n", s.find('a'));
printf("字符 a 在 s 的 %d 位置第一次出現\n", s.find('a'));
printf("字符串 t 在 s 的 %lu 位置第一次出現\n", s.find(t));
printf("在 s 中自 pos 位置起字符串 u 第一次出現在 %lu 位置", s.find(u, pos));

輸出:

1
2
3
4
5
字符 I 在 s 的 1 位置第一次出現
字符 a 在 s 的 18446744073709551615 位置第一次出現 // 即為 size_t(-1),具體數值與平台有關。
字符 a 在 s 的 -1 位置第一次出現 // 強制轉換為 int 類型則正常輸出 -1
字符串 t 在 s 的 0 位置第一次出現
在 s 中自 pos 位置起字符串 u 第一次出現在 6 位置

截取子串

substr(pos, len) 函數的參數返回從 pos 位置開始截取最多 len 個字符組成的字符串(如果從 pos 開始的後綴長度不足 len 則截取這個後綴)。

示例:

1
2
3
4
5
string s = "OI Wiki", t = "OI";
printf("從字符串 s 的第四位開始的最多三個字符構成的子串是 %s\n",
       s.substr(3, 3).c_str());
printf("從字符串 t 的第二位開始的最多三個字符構成的子串是 %s",
       t.substr(1, 3).c_str());

輸出:

1
2
從字符串 s 的第二位開始的最多三個字符構成的子串是 Wik
從字符串 t 的第二位開始的最多三個字符構成的子串是 I

插入/刪除字符(串)

insert(index,count,ch)insert(index,str) 是比較常見的插入函數。它們分別表示在 index 處連續插入 count 次字符串 ch 和插入字符串 str

erase(index,count) 函數將字符串 index 位置開始(含)的 count 個字符刪除(若不傳參給 count 則表示刪去 index 位置及以後的所有字符)。

示例:

1
2
3
4
5
6
7
8
9
string s = "OI Wiki", t = " Wiki";
char u = '!';
s.erase(2);
printf("從字符串 s 的第三位開始刪去所有字符後得到的字符串是 %s\n", s.c_str());
s.insert(2, t);
printf("在字符串 s 的第三位處插入字符串 t 後得到的字符串是 %s\n", s.c_str());
s.insert(7, 3, u);
printf("在字符串 s 的第八位處連續插入 3 次字符串 u 後得到的字符串是 %s",
       s.c_str());

輸出:

1
2
3
從字符串 s 的第三位開始刪去所有字符後得到的字符串是 OI
在字符串 s 的第三位處插入字符串 t 後得到的字符串是 OI Wiki
在字符串 s 的第八位處連續插入 3 次字符串 u 後得到的字符串是 OI Wiki!!!

替換字符(串)

replace(pos,count,str)replace(first,last,str) 是比較常見的替換函數。它們分別表示將從 pos 位置開始 count 個字符的子串替換為 str 以及將以 first 開始(含)、last 結束(不含)的子串替換為 str,其中 firstlast 均為迭代器。

示例:

1
2
3
4
5
string s = "OI Wiki";
s.replace(2, 5, "");
printf("將字符串 s 的第 3~7 位替換為空串後得到的字符串是 %s\n", s.c_str());
s.replace(s.begin(), s.begin() + 2, "NOI");
printf("將字符串 s 的前兩位替換為 NOI 後得到的字符串是 %s", s.c_str());

輸出:

1
2
將字符串 s 的第 3~7 位替換為空串後得到的字符串是 OI
將字符串 s 的前兩位替換為 NOI 後得到的字符串是 NOI