跳轉到內容

C++ 程式設計/程式碼/IO/流/字串

來自華夏公益教科書,自由的教科書

字串類

[編輯 | 編輯原始碼]

字串類是 C++ 標準庫的一部分,用於方便地操作字元序列,以取代處理字串的靜態、不安全的 C 方法。要在程式中使用字串類,必須包含 <string> 標頭檔案。標準庫字串類可以透過 std 名稱空間 訪問。

基本模板類是 basic_string<>,其標準特化是 stringwstring

基本用法

[編輯 | 編輯原始碼]

宣告一個 std 字串可以透過以下兩種方法之一完成

using namespace std;
string std_string;

or
 
std::string std_string;

文字 I/O

[編輯 | 編輯原始碼]

本節只處理鍵盤和文字輸入。還有許多其他輸入可以讀取(滑鼠移動和按鈕點選等),但這些內容在本節中不會涉及,即使是讀取鍵盤上的特殊鍵也會被排除在外。

也許字串類最基本的使用方式是讀取使用者的文字並將其寫入螢幕。在標頭檔案iostream中,C++ 定義了一個名為 cin 的物件,它處理輸入的方式與 cout 處理輸出的方式非常相似。

// snipped designed to get an integer value from the user
int x; 
std::cin >> x;

>> 運算子將導致執行停止並等待使用者輸入。如果使用者輸入有效的整數,它將被轉換為整數值並存儲在 x 中。

如果使用者輸入的不是整數,編譯器不會報錯。相反,它會在x中保留舊內容(一個“隨機”的無意義值)並繼續執行。

然後可以將其擴充套件到以下程式

#include <iostream>
#include <string>

int main(){
    std::string name;
    std::cout << "Please enter your first name: ";
    std::cin >> name;
    std::cout << "Welcome " << name << "!" << std::endl;

    return 0;
}


雖然字串可以包含任何字元的序列,包括空格和空字元,但在使用 cin 和提取運算子(>>)將內容讀入字串時,只會儲存第一個空格之前的字元。或者,如果需要整行文字,可以使用 getline 函式

    std::getline(std::cin, name);

獲取使用者輸入

[編輯 | 編輯原始碼]

幸運的是,有一種方法可以檢查輸入語句是否成功。我們可以呼叫 cin 上的 good 函式來檢查所謂的流狀態。good 返回一個 bool 值:如果為 true,則上次輸入語句成功。如果不是,我們知道之前的某個操作失敗了,而且下一個操作也會失敗。

因此,從使用者獲取輸入可能看起來像這樣

#include <iostream>
using namespace std;
int main () 
{ 
  int x; 
 
  // prompt the user for input 
  cout << "Enter an integer: "; 
 
  // get input 
  cin >> x; 
 
  // check and see if the input statement succeeded 
  if (cin.good() == false) { 
    cout << "That was not an integer." << endl; 
    return -1; 
  } 
 
  // print the value we got from the user 
  cout << x << endl; 
  return 0; 
}

cin 也可以用來輸入字串

string name;

cout << "What is your name? "; 
cin >> name; 
cout << name << endl;

與標準 C 庫中的 scanf() 函式一樣,此語句只獲取輸入的第一個單詞,並將剩餘的單詞留給下一個輸入語句。因此,如果您執行此程式並輸入您的全名,它只會輸出您的名字。

您可能還會注意到 >> 運算子沒有按預期處理錯誤(例如,如果您在數字提示中不小心輸入了您的姓名)。由於這些問題,讀取一行文字並使用該行作為輸入可能更合適 - 這是使用名為 getline 的函式來執行的。

string name;

cout << "What is your name? "; 
getline (cin, name); 
cout << name << endl;

getline 的第一個引數是 cin,它表示輸入來自哪裡。第二個引數是您要儲存結果的字串變數的名稱。

getline 會讀取整行,直到使用者按下回車鍵或 Enter 鍵。這對於輸入包含空格的字串很有用。

事實上,getline 通常用於獲取任何型別的輸入。例如,如果您想讓使用者輸入一個整數,您可以輸入一個字串,然後檢查它是否是一個有效的整數。如果是,則可以將其轉換為整數值。如果不是,您可以列印一條錯誤訊息並要求使用者重試。

要將字串轉換為整數,可以使用在標頭檔案 cstdlib 中定義的 strtol 函式。(請注意,與 strtol 相比,舊函式 atoi 並不安全,而且功能也不如 strtol。)

如果您仍然需要 >> 運算子的功能,則需要建立字串流,如<sstream>中所述。此流的使用將在後面的章節中討論。

更高階的字串操作

[編輯 | 編輯原始碼]
Clipboard

要做的事情
詳細介紹常用的 std::string 成員函式(部分完成)


我們將使用這個虛擬字串作為我們一些示例。

string str("Hello World!");

這呼叫帶有 const char* 引數的預設建構函式。預設建構函式建立一個不包含任何內容的字串,即沒有字元,甚至沒有 '\0'(但是 std::string 不是以空字元結尾的)。

string str2(str);

將觸發複製建構函式。std::string 瞭解如何對它儲存的字元進行深度複製。

string str2 = str;

這將使用賦值運算子複製字串。此程式碼的效果與上面的示例中使用複製建構函式相同。

string::size_type string::size() const;
string::size_type string::length() const;

例如,您可以執行以下操作

string::size_type strSize =  str.size();
string::size_type strSize2 = str2.length();

size()length() 方法都返回字串物件的大小。兩者之間沒有明顯的區別。請記住,字串中的最後一個字元是 size() - 1,而不是 size()。就像在 C 風格的字串和陣列中一樣,std::string 從 0 開始計數。

ostream& operator<<(ostream &out, string &str);
istream& operator>>(istream &in, string &str);

移位運算子(>><<)已被過載,因此您可以對 istreamostream 物件執行 I/O 操作,最值得注意的是 coutcin 和檔案流。因此,您可以像這樣執行控制檯 I/O

std::cout << str << endl;
std::cin >> str;

istream& getline (istream& in, string& str, char delim = '\n');

或者,如果您想一次讀取整行,請使用 getline()。請注意,這不是一個成員函式。getline() 將從輸入流 in 中檢索字元並將其分配給 str,直到遇到 EOFdelimgetline 將在追加資料之前重置輸入字串。delim 可以設定為任何 char 值,並用作通用分隔符。以下是一些示例用法

#include <fstream>
//open a file
std::ifstream file("somefile.cpp");
std::string data, temp;

while( getline(file, temp, '#')) //while data left in file
{
    //append data
    data += temp;
}

std::cout << data;

由於 getline 的工作方式(即它返回輸入流),因此您可以巢狀多個 getline() 呼叫來獲取多個字串;但是,這可能會顯著降低可讀性。

運算子

[編輯 | 編輯原始碼]
char& string::operator[](string::size_type pos);

string 中的 Chars 可以使用過載的下標 ([]) 運算子直接訪問,就像在 char 陣列中一樣。

std::cout << str[0] << str[2];

列印 "Hl"。

std::string 支援從舊的 C 字串型別 const char* 轉換。你也可以將一個簡單的 char 分配或追加到一個字串中。將 char* 分配給 string 就像這樣

str = "Hello World!";

如果你想逐個字元地進行,你也可以使用

str = 'H';

毫不奇怪,operator+operator+= 也被定義了!你可以將另一個 string、一個 const char* 或一個 char 追加到任何字串中。

比較運算子 >, <, ==, >=, <=, != 都對字串執行比較操作,類似於 C 的 strcmp() 函式。這些返回一個真/假值。

if(str == "Hello World!")
{
 std::cout << "Strings are equal!";
}


搜尋字串

[編輯 | 編輯原始碼]
string::size_type string::find(string needle, string::size_type pos = 0) const;

你可以使用 find() 成員函式在另一個字串中查詢字串的第一個出現位置。find() 將從位置 pos 開始在 this 中查詢 needle,並返回 needle 第一次出現的位置。例如

std::string haystack = "Hello World!";
std::string needle = "o";
std::cout << haystack.find(needle);

將簡單地列印 "4",這是 str 中 "o" 第一次出現的位置索引。如果我們想要 "World" 中的 "o",我們需要修改 pos 指向第一個出現位置之後。str.find(find, 4) 將返回 4,而 str.find(find, 5) 將返回 7。如果子字串未找到,find() 將返回 std::string::npos。這個簡單的程式碼在一個字串中搜索所有 "wiki" 的出現位置,並列印它們的位置

std::string wikistr = "wikipedia is full of wikis (wiki-wiki means fast)";
for(string::size_type i = 0, tfind; (tfind = wikistr.find("wiki", i)) != string::npos; i = tfind + 1)
{
 std::cout << "Found occurrence of 'wiki' at position " << tfind << std::endl;
}

string::size_type string::rfind(string needle, string::size_type pos = string::npos) const;

函式 rfind() 的工作原理類似,只是它返回傳遞字串的最後出現位置。

插入/刪除

[編輯 | 編輯原始碼]
string& string::insert(size_type pos, const string& str);

你可以使用 insert() 成員函式將另一個字串插入到一個字串中。例如

string newstr = " Human";
str.insert (5,newstr);

將返回 Hello Human World!

string& string::erase(size_type pos, size_type n);

你可以使用 erase() 從字串中刪除子字串。例如

str.erase (5,6);

將返回 Hello!

string& string::substr(size_type pos, size_type n);

你可以使用 substr() 從字串中提取子字串。例如

string str = "Hello World!";
string part = str.substr(6,5);

將返回 World

向後相容性

[編輯 | 編輯原始碼]
const char* string::c_str() const;
const char* string::data() const;

為了與只接受 char* 引數的 C/C++ 函式向後相容,你可以使用成員函式 string::c_str()string::data() 返回一個臨時的 const char* 字串,你可以將其傳遞給函式。這兩個函式之間的區別是,c_str() 返回一個以 null 結尾的字串,而 data() 不一定返回一個以 null 結尾的字串。因此,如果你的舊函式需要一個以 null 結尾的字串,請使用 c_str(),否則使用 data()(並且可能還要將字串的長度作為引數傳遞)。

字串連線

[編輯 | 編輯原始碼]

字串可以透過簡單地使用 + 運算子連線(追加)在一起。

string firstString = "Hello";
string secondString = " World!";
string finalString = firstString  + secondString;
cout << finalString << endl;

這裡的輸出將是 "Hello World"

追加字串

[編輯 | 編輯原始碼]

需要注意的是,除了 + 運算子或連線之外,還可以使用 .append(str2) 類成員函式將一個字串連線到另一個字串。str2 物件可以是字串物件或 C 字串。這將把括號中的字串新增到呼叫 append 的字串中。

還應該注意,append 函式可以用於在字串中的特定字元位置追加字串。如果程式設計師輸入 str.append(str2, p, n) ,則從字串 str2 中位置 p 開始的 n 個字元將被追加到 str 的末尾。例如,在以下程式碼中,有兩個字串。從第二個字串中位置 8 開始的 5 個字元將被追加到第一個字串 str 的末尾。

string str("Watch out for ");
string str2("Llamas, Bears, and Telemarketers!");

str.append(str2, 8, 5);
cout << str << endl;

上面的程式碼將在第一個字串的末尾追加單詞 Bears,然後在螢幕上列印 Watch out for Bears


字串轉換為有符號整數

[編輯 | 編輯原始碼]

有時我們想將字串轉換為數字。為此,我們可以使用 stoi() 函式,它接受一個字串作為引數並返回該值。

string exString1 = "12023";
string exString2 = "1.23249";
string exString3 = "1232 test";

要將這些字串轉換為數字,我們將字串變數的 stoi 儲存到一個整數變數中。

int exInt1 = stoi(exString1);
int exInt2 = stoi(exString2);
int exInt3 = stoi(exString3);
cout << "Before stoi string:" << exString1 << " and after stoi int:" << exInt1 << endl;
cout << "Before stoi string:" << exString2 << " and after stoi int: " << exInt2 << endl;
cout << "Before stoi string:" << exString3 << " and after stoi int:" << exInt3 << endl;

輸出將是:Before stoi string :12023 and after stoi int: 12023 Before stoi string :1 and after stoi int: 1 Before stoi string :1232 and after stoi int: 1232

整數轉換為字串

[編輯 | 編輯原始碼]

如果我們想做相反的事情,將一個整數轉換為一個字串,我們可以使用 to_string() 函式,它接受一個整數作為引數,並返回該整數作為字串。

int exInt = 12023;

要將這個整數轉換為字串,我們呼叫 to_string() 函式。整數變數作為引數傳遞給函式。然後該函式將返回該整數作為字串,然後可以將其分配給一個字串變數。

string exString = to_string(exInt);
cout << "Before to_string int:" << exInt << " and after to_string string:" << exString << endl;

輸出將是:Before to_string int:12023 and after to_string string:12023

字串格式化

[編輯 | 編輯原始碼]

字串只能追加到其他字串,但不能追加到數字或其他資料型別,因此類似 std::string("Foo") + 5 這樣的程式碼將不會產生一個內容為 "Foo5" 的字串。要將其他資料型別轉換為字串,存在類 std::ostringstream,它位於標頭檔案 <sstream> 中。std::ostringstream 的行為與 std::cout 完全相同,唯一的區別是輸出不會像作業系統提供的當前標準輸出那樣,而是輸出到一個內部緩衝區中,該緩衝區可以透過 std::ostringstream::str() 方法轉換為 std::string

#include <iostream>
#include <sstream>

int main()
{ 
    std::ostringstream buffer;

    // Use the std::ostringstream just like std::cout or other iostreams
    buffer << "You have: " << 5 << " Helloworlds in your inbox";
 
    // Convert the std::ostringstream to a normal string
    std::string text = buffer.str();
 
    std::cout << text << std::endl;
 
    return 0;
}

高階用法

[編輯 | 編輯原始碼]
Clipboard

要做的事情
對 basic_string 等的模板引數

華夏公益教科書