【不是惡夢的開始,而是再度的精進。】
對於字串的處理除了使用字元陣列,還有另一種較好的方法,就是使用 string 物件。
標頭檔string定義了string型態,string型態是由類別(class)定義。基本上類別只是引入一種新型態而已,實際上使用類別定義的型態和基本資料型態的使用並無差異。類別型態的實體通常稱為物件(object)而不是變數,雖然string不是基本的資料型態,但它是ANSI標準的一部份,所以你可以將它視為你可用的另一種資料型態,而且string物件的處理方式和基本資料型態變數的處理方式完全相同。
string型態的物件內容是char型態的字元字串,可以是空字串。
string型態的物件宣告敘述格式如下:
string names;
這敘述宣告了 names 為 string 物件,但我們並沒有初值化字串物件,所以它表示的字串沒有字元,長度為0。
初值化 string 物件,格式如下:
string names = "isabella";
也可以用函數表示法初值化物件,格式如下:
string names ("isabella");
從上面兩個例子中可以看出,儲存的字串不需要字串結數字元,string物件會記錄它代表之字串的長度,用函數 length() 來取得 string 物件的長度,無須引數,格式如下
cout << names.length();
例:
#include<iostream>
using namespace std;
int main(int argc, char** argv)
{
string names = "isabella";
cout << "\n names 長度為: " << names.length() << "\n";
return 0;
}
結果輸出:names 長度為: 8
此範例字串的長度是8。字串不只是可記載單字,也可以記載句子,空格也計入一個長度。
運算式 names.length() 中的句點稱為成員存取運算子,或是稱點運算子,它表示函數 lenght() 是 names 物件的成員,這是類別的範圍,看看有沒有機會讀到那裏。
連結字串:
我們可以用加法運算子來結合兩個字串物件,或一個字串物件加字串常數。不可以字串常數加字串常數再加字串物件,而是要掉過頭來在第一個加法運算子的兩邊先有一個字串物件,編譯器才不會產生錯誤訊息。
例:
#include<iostream>
using namespace std;
int main(int argc, char** argv)
{
string llkk = "LKK";
string young = "is young";
string lala = "Does " + llkk + " " + young + "... " + "?";
cout << "\n" << lala << "\n" ;
return 0;
}
結果輸出:Does LKK is young... ?
在程式碼中
string lala = "Does " + llkk + " " + young + "... " + "?";
第一個加法運算子的左邊是字串常數,右邊是字串物件,這樣可以成立的。
而最右邊的程式碼
+ "... " + "?"
因為不是第一個加法運算子,所以在加法運算子的兩側都是字串常數 "... " 以及 "?",也是合法的。
若把程式碼改成
string lala = llkk + " " + young + "... " + "?";
第一個加法運算子的左右兩邊各是字串物件和物件常數,這樣也可以成立的。
但是若不小心手殘,把程式碼寫成
string lala = "llkk" + " " + young + "... " + "?";
第一個加法運算子的兩邊都是字串常數時,就會產生編譯錯誤。
再一例:
#include<iostream>
using namespace std;
int main(int argc, char** argv)
{
string names;
cout << "What's your name ? ";
cin >> names;
cout << "\nHi," + names + ", how are you ? \n\n";
system("pause");
return 0;
}
結果輸出:
What's your name ? Susan
Hi,Susan, how are you ?
大體上來說,程式碼可以編譯也可以執行,但小瑕疵點在於輸入的名字不可以有空白字,外國人可能把名字和姓氏都一起打上,這時候就會有一個空格來區分名和姓,而C++中的串流萃取運算子 >> 是以處理 char 陣列的方式處理字串,當遇到第一個空白字元時就會停止讀取字元,所以當輸入 Phil Hardy 時,cin >> names; 就只接收到 Phil,Hardy 就被放生了。
這時候程式碼中就不適合用 cin >> names; 了,改用 getline(cin, names); 來取代它,如此一來問題就解決了。
結果輸出:
What's your name ? Phil Hardy
Hi,Phil Hardy, how are you ?
存取字串的字元:
我們可以用中括號和索引值參考 string 物件中的特定字元,就像再處理字元陣列一樣, string 物件的第一個字元的索引值為0,例如要參考 string texts; 中 texts 的第三個字元的運算式就是 texts[2],我們也可以把這個運算式放在運算子的左邊,這樣就可以存取或修改個別字元了。
例:
#include<iostream>
using namespace std;
int main(int argc, char** argv)
{
string texts;
cout << "\n輸入一行英文句子 : ";
getline(cin, texts);
for(int i = 0; i < texts.length(); i++)
switch(tolower(texts[i]))
{
case 'a': texts[i] = '8';
break;
case 'b': texts[i] = '5';
break;
}
cout << "\n你輸入的字串變成了 : " << texts << "\n";
return 0;
}
結果輸出:
輸入一行英文句子 : to boost morale
你輸入的字串變成了 : to 5oost mor8le
存取字串的子字串:
用函數 substr() 可取得 string 物件的子字串,其格式如下:
子字串 = 原始字串.substr(子字串開始索引位置, 子字串的字元數目)
例:
string sentence = "Hi, Good morning!";
string element = sentence.substr(4, 4);
這樣就可以取得子字串 element 為 Good。
當我們把子字串的字元數目設定到大於原始字串的長度時,函數會回傳到原始字串結束的所有的字元。
例:
string element = sentence.substr(4, 30);
這樣就可以取得子字串 element 為 Good morning!。
另外,我們若省略子字串的字元數目,將會和把子字串的字元數目設定到大於原始字串的長度時相同。
例:
string element = sentence.substr(4);
這樣仍是取得子字串 element 為 Good morning!。
例:
#include<iostream>
using namespace std;
int main(int argc, char** argv)
{
string sentence = "Hi, Good morning!";
string element = sentence.substr(4, 8);
cout << "子字串為: " << element;
element = sentence.substr(4, 30);
cout << "\n\n子字串為: " << element;
element = sentence.substr(4);
cout << "\n\n子字串為: " << element;
return 0;
}
結果輸出:
子字串為: Good mor
子字串為: Good morning!
子字串為: Good morning!
比較字串:
在比較字串時,我們也可以用所有的比較運算子, > 、 >= 、 < 、 <= 、 == 、 !=
它們可用於比較 string 型態的兩個物件,或是比較 string 物件和字串文字或存在 char 陣列的 C-格式字串。
當發現不同的字元時,會對字元碼作數字的比較以決定哪一個字串在前。
若字元都一樣,但字串的長度不同時,較短的字串則小於較長的字串。
若兩個字串有相同的字元數且對應的字元都相等,則它們是相等的。
因為比對字元碼會是大小寫相異。
例:
#include<iostream>
using namespace std;
int main(int argc, char** argv)
{
string name1 = "Mary";
string name2 = "George";
if(name1 > name2)
cout << name1 << " 大於 " << name2;
else
cout << name1 << " 小於 " << name2;
return 0;
}
結果輸出: Mary 大於 George
.
留言列表