1. 程式人生 > >C++ string 類詳解

C++ string 類詳解

常見 連續 可見 ras def 位置 primer 問題 iter

  字符串是存儲在內存的連續字節中的一系列字符。C++ 處理字符串的方式有兩種,一種來自 C 語言,常被稱為 C-風格字符串,另一種是基於 string 類庫的字符串處理方式。C 風格字符串的處理可以參考 https://www.cnblogs.com/tongye/p/10688941.html ,本文著重介紹 string 類庫的使用。

一、string 類簡介

  C++ 中提供了專門的頭文件 string(註意不是 string.h,這個是 C 風格字符串相關函數的頭文件),來支持 string 類型。string 類定義隱藏了字符串的數組性質,讓我們可以像處理普通變量那樣處理字符串。string 對象和字符數組之間的主要區別是:可以將 string 對象聲明為簡單變量,而不是數組

1.1 string 類幾種常見的構造函數:

1)string(const char *s) :將 string 對象初始化為 s 指向的字符串

string str("Hello!");

2)string(size_type n,char c) :創建一個包含 n 個元素的 string 對象,其中每個元素都被初始化為字符 c

string str(10,a);

3)string(const string &str) :將一個 string 對象初始化為 string 對象 str(復制構造函數)

string str1("hello!");
string str2(str1);

4)string() :創建一個默認的 string 對象,長度為 0(默認構造函數)

string str;     // 創建一個空的 string 對象

  string 類的設計允許程序自動處理 string 的大小,因此,上述代碼創建了一個長度為 0 的string 對象,但是向 str 中寫入數據時,程序會自動調整 str 的長度。因此,與使用數組相比,使用 string 對象更方便,也更安全。

1.2 用 C 語言風格初始化 string 對象:

  C++ 允許使用 C 語言風格來初始化 string 對象:

string
str = "hello!";

二、獲取 string 對象的長度

  在 C 語言中,使用 strlen 函數獲取字符串的長度。在 C++ 中,可以使用 string.size() 函數或 string.length() 函數來獲得 string 對象的長度。在 C++ 標準庫中,兩者的源代碼如下:

  size_type   __CLR_OR_THIS_CALL   length()   const   
  { //   return   length   of   sequence   
  return   (_Mysize);   
  }   
    
  size_type   __CLR_OR_THIS_CALL   size()   const   
  { //   return   length   of   sequence   
  return   (_Mysize);   
  }

  可見,這兩個方法是完全一樣的,並沒有區別。length() 方法是 C 語言習慣保留的,size() 方法則是為了兼容 STL 容器而引入的。

string str("Hello,World!");
int strLen1 = str.length();
int strLen2 = str.size();

三、復制 string 對象

  在 C 語言中,使用 strcpy、strncpy 函數來實現字符串的復制。在 C++ 中則方便很多,可以直接將一個 string 對象賦值給另一個 string 對象,即:

string str1("Hello,World!");
string str2;
str2 = str1;

  由於 string 類會自動調整對象的大小,因此不需要擔心目標數組不夠大的問題。

四、string 對象的拼接和附加

  在 C 語言中,使用 strcat、strncat 函數來進行字符串拼接操作。在 C++ 中也有多種方法來實現字符串拼接和附加操作:

4.1 使用 + 操作符拼接兩個字符串

string str1("hello ");
string str2("world!");
string str3 = str1 + str2;

4.1 使用 += 操作符在字符串後面附加內容

  可以使用 += 來在一個 string 對象後面附加一個 string 對象、字符以及 C 風格的字符串:

string str1("hello ");
string str2("world!\n");
str1
+= str2; str1 += "nice job\n"; str1 += a;

4.2 使用 string.append() 函數

  可以使用 string.append() 函數來在一個 string 對象後面附加一個 string 對象或 C 風格的字符串:

string str1 = "hello,world!";
string str2 = "HELLO,WORLD!";
    
str1.append(str2);
str1.append("C string");

4.3 使用 string.push_back() 函數

  可以使用 string.push_back() 函數來在一個 string 對象後面附加一個字符:

string str("Hello");
str.push_back(a);

五、string 對象的比較

  在 C 語言中,使用 strcmp、strncmp 函數來進行字符串的比較。在 C++ 中,由於將 string 對象聲明為了簡單變量,故而對字符串的比較操作十分簡單了,直接使用關系運算符(==、!=、<、<=、>、>=)即可:

#include <string>
#include <iostream>

using namespace std;

int main() 
{
    string str1("hello");
    string str2("hello");

    if (str1 == str2)
        cout << "str1 = str2" << endl;
    else if (str1 < str2)
        cout << "str1 < str2" << endl;
    else
        cout << "str1 > str2" << endl;

    return 0;
}

  當然,也可以使用類似 strcmp 的函數來進行 string 對象的比較,string 類提供的是 string.compare() 方法,函數原型如下:

int compare(const string&str) const;

int compare(size_t pos,size_t len,const string&str)const;    // 參數 pos 為比較字符串中第一個字符的位置,len 為比較字符串的長度

int compare(size_t pos,size_t len,const string&str, size_t subpos,size_t sublen)const;

int compare(const char * s)const;

int compare(size_t pos,size_t len,const char * s)const;

int compare(size_t pos,size_t len,const char * s,size_t n)const;

  compare 方法的返回值如下:

1)返回 0,表示相等;

2)返回結果小於 0,表示比較字符串中第一個不匹配的字符比源字符串小,或者所有字符都匹配但是比較字符串比源字符串短;

3)返回結果大於 0,表示比較字符串中第一個不匹配的字符比源字符串大,或者所有字符都匹配但是比較字符串比源字符串長。

六、使用 string.substr() 函數來獲取子串

  可以使用 string.substr() 函數來獲取子串,string.substr() 函數的定義如下:

string substr(size_t pos = 0,size_t len = npos)const;

  其中,pos 是子字符串的起始位置(索引,第一個字符的索引為 0),len 是子串的長度。這個函數的功能是:復制一個 string 對象中從 pos 處開始的 len 個字符到 string 對象 substr 中去,並返回 substr。

string str("Hello,World!");
string subStr = str.substr(3,5);
cout << subStr << endl;

  這段代碼的輸出結果為:"lo,Wo"。

七、訪問 string 字符串的元素

  可以像 C 語言中一樣,將 string 對象當做一個數組,然後使用數組下標的方式來訪問字符串中的元素;也可以使用 string.at(index) 的方式來訪問元素(索引號從 0 開始):

string str("Hello,World!");
cout << str[1] << endl;      // 使用數組下標的方式訪問 string 字符串的元素
cout << str.at(1) << endl;     // 使用 at 索引訪問 string 字符串的元素

八、string 對象的查找操作

8.1 使用 string.find() 方法查找字符

  find 方法的函數原型如下:

1)從字符串的 pos 位置開始(若不指定 pos 的值,則默認從索引 0 處開始),查找子字符串 str。如果找到,則返回該子字符串首次出現時其首字符的索引;否則,返回 string::npos:

size_type find (const string& str, size_type pos = 0) const;

2)從字符串的 pos 位置開始(若不指定 pos 的值,則默認從索引 0 處開始),查找子字符串 s。如果找到,則返回該子字符串首次出現時其首字符的索引;否則,返回 string::npos:  

size_type find (const char *s, size_type pos = 0) const;

3)從字符串的 pos 位置開始(若不指定 pos 的值,則默認從索引 0 處開始),查找 s 的前 n 個字符組成的子字符串。如果找到,則返回該子字符串首次出現時其首字符的索引;否則,返回 string::npos:

size_type find (const char *s, size_type pos, size_type n);

4)從字符串的 pos 位置開始(若不指定 pos 的值,則默認從索引 0 處開始),查找字符 ch 。如果找到,則返回該字符首次出現的位置;否則,返回 string::npos:

size_type find (char ch, size_type pos = 0) const;

  舉個查找子字符串的例子(查找字符的代碼與這一樣,只需要將 find 函數的參數換成字符即可):

#include <string>
#include <iostream>

using namespace std;

int main() 
{
    string str("cat,dog,cat,pig,little cat,hotdog,little pig,angry dog");
    size_t catPos = str.find("cat",0);

    if (catPos == string::npos) {
        printf("沒有找到字符串\n");
        return 0;
    }

    while (catPos != string::npos) {
        cout << "在索引 " << catPos << " 處找到字符串" << endl;
        catPos = str.find("cat", catPos + 1);
    }
    return 0;
}

  程序輸出結果如下:

技術分享圖片

  

8.2 string.rfind()

  string.rfind() 與 string.find() 方法類似,只是查找順序不一樣, string.rfind() 是從指定位置 pos (默認為字符串末尾)開始向前查找,直到字符串的首部,並返回第一次查找到匹配項時匹配項首字符的索引。換句話說,就是查找子字符串或字符最後一次出現的位置。還是以上面的程序為例,稍作修改:

#include <string>
#include <iostream>

using namespace std;

int main() 
{
    string str("cat,dog,cat,pig,little cat,hotdog,little pig,angry dog");
    size_t catPos = str.rfind("cat",str.length()-1);

    if (catPos == string::npos) {
        printf("沒有找到字符串\n");
        return 0;
    }

    while (catPos != string::npos) {
        cout << "在索引 " << catPos << " 處找到字符串" << endl;
        catPos = str.rfind("cat", catPos - 1);
        if (catPos == 0) {
            cout << "在索引 " << catPos << " 處找到字符串" << endl;
            break;
        }
    }
    return 0;
}

  程序輸出結果如下:

技術分享圖片

  可以看到,rfind 方法是從字符串末開始查找的。

8.3 string.find_first_of()

  string.find_first_of() 方法在字符串中從指定位置開始向後(默認為索引 0 處)查找參數中任何一個字符首次出現的位置。舉個例子說明:

#include <string>
#include <iostream>

using namespace std;

int main() 
{
    string str("cat,dog,cat,pig,little cat,hotdog,little pig,angry dog");
    size_t pos = str.find_first_of("zywfgat");

    if (pos == string::npos) {
        printf("沒有匹配到\n");
        return 0;
    }
    else
        cout << "在索引 " << pos << " 處匹配到" << endl;

    return 0;
}

  程序輸出結果是:在索引 1 處匹配到。所查找的字符串 zywfgat 中,第一次出現在字符串 str 中的字符是 ‘a‘,該字符在 str 中的索引是 1.

8.4 string.find_last_of()

  string.find_last_of() 方法在字符串中查找參數中任何一個字符最後一次出現的位置(也就是從指定位置開始往前查找,第一個出現的位置)。

8.5 string.find_first_not_of()

  string.find_first_not_of() 方法在字符串中查找第一個不包含在參數中的字符。

8.6 string.find_last_not_of()

  string.find_last_not_of() 方法在字符串中查找最後一個不包含在參數中的字符(從指定位置開始往前查找,第一個不包含在參數中的字符)。

九、string 對象的插入和刪除操作

9.1 使用 string.insert() 進行插入操作

  函數原型如下:

string&insert(size_t pos,const string&str);   // 在位置 pos 處插入字符串 str

string&insert(size_t pos,const string&str,size_t subpos,size_t sublen); // 在位置 pos 處插入字符串 str 的從位置 subpos 處開始的 sublen 個字符

string&insert(size_t pos,const char * s);    // 在位置 pos 處插入字符串 s

string&insert(size_t pos,const char * s,size_t n); // 在位置 pos 處插入字符串 s 的前 n 個字符

string&insert(size_t pos,size_t n,char c);      // 在位置 pos 處插入 n 個字符 c

iterator insert (const_iterator p, size_t n, char c); // 在 p 處插入 n 個字符 c,並返回插入後叠代器的位置

iterator insert (const_iterator p, char c);       // 在 p 處插入字符 c,並返回插入後叠代器的位置

  舉個例子:

#include <string>
#include <iostream>

using namespace std;

int main() 
{
    string str("abcdefgh");
    str.insert(1,"INSERT");        // 在位置 1 處插入字符串 "INSERT"
    cout << str << endl;

    str.insert(10, 5, A);        // 在位置 10 處插入 5 個字符 ‘A‘
    cout << str << endl;
    return 0;
}

  輸出結果如下:

技術分享圖片

9.2 使用 string.erase() 進行元素刪除操作

  函數原型如下:

string& erase (size_t pos = 0, size_t len = npos);   // 刪除從 pos 處開始的 n 個字符

iterator erase (const_iterator p);            // 刪除 p 處的一個字符,並返回刪除後叠代器的位置

iterator erase (const_iterator first, const_iterator last); // 刪除從 first 到 last 之間的字符,並返回刪除後叠代器的位置

  舉個例子:

#include <string>
#include <iostream>

using namespace std;

int main() 
{
    string str("Hello,World!");
    str.erase(5,6);                    // 刪除從索引位置 5 開始的 6 個字符
    cout << "str 為:" << str << endl;

    return 0;
}

  關於 erase() 函數的用法可以參考 https://www.cnblogs.com/liyazhou/archive/2010/02/07/1665421.html

十、string 對象的一些其他操作

10.1 使用 getline() 函數來獲取 string 輸入

string str;

getline(cin,str);    // 從輸入流中讀取一行數據到 str

10.2 使用 empty() 函數判斷字符串是否為空

string str;

if(str.empty()){
    cout << "字符串為空" << endl;  
}

  string.empty() 函數,若字符串為空,則返回真,否則返回假。

10.3 使用 swap 函數交換兩個字符串

#include <string>
#include <iostream>

using namespace std;

int main() 
{
    string str1 = "hello,world!";
    string str2 = "HELLO,WORLD!";

    str1.swap(str2);

    cout << str1 << endl;
    cout << str2 << endl;

    return 0;
}

參考資料:

C++ Primer Plus(第六版)

C++ string 類詳解