460 likes | 614 Views
22. 物件導向的字串處理. 內建的完整 類別 string 具有 豐富的成員函數,能以物件導向的語法處理字串,讓程式設計者免除空間安排及安插結尾符號等瑣碎的工作。. Chap 22 物件導向的字串處理. 22.1 C 風格的字串和物件導向的 string 類別 22.2 String 物件的定義 22.3 字串的更改、清除、剪接與部份複製 22.4 字串之間的比對和比較 22.5 字串物件與 C-style 字串的互換. 22.1 C 風格的字串和物件導向的 string 類別. C-style string (C 風格的字串 )
E N D
22 物件導向的字串處理 • 內建的完整類別string具有豐富的成員函數,能以物件導向的語法處理字串,讓程式設計者免除空間安排及安插結尾符號等瑣碎的工作。
Chap 22物件導向的字串處理 • 22.1C風格的字串和物件導向的string類別 • 22.2String物件的定義 • 22.3 字串的更改、清除、剪接與部份複製 • 22.4 字串之間的比對和比較 • 22.5 字串物件與C-style字串的互換
22.1 C風格的字串和物件導向的string 類別 • C-style string (C風格的字串) 由資料型態為char構成的一維陣列,結尾處加上 ‘\0’ 做為字串的結束符號。 • 宣告C風格字串的三種方式 char s1[20] = "Hello, 您好!"; // 陣列式的宣告 char* ps2 = "Hello, 您好!"; // 指標式的宣告 char s3[10] = {'G', 'o', '!', '\0'}; // 列舉陣列元素式的宣告
使用自動設定字元陣列長度的語法宣告C風格的字串使用自動設定字元陣列長度的語法宣告C風格的字串 // 自動設定字元陣列的長度 char s4[] = "Hello, 您好!"; char s5[] = {'\n', 'G', 'o', '!' , '\0'};
物件導向的string類別 • 在STL (the Standard Template Library) 中定義。使用前要在程式開頭處加上 #include <string> 以含入標頭檔 <string>,完成string類別的宣告。 • 可以動態地配置記憶空間。 • 有完整的成員函數,提供了許多方便的運算子。
22.2 定義String物件 (1/2) string S1; // 定義一個空的string物件S1 string S2, S3, S4; // 同時定義三個空的string物件 string S5("A 是 123"); // S5的容是 "A是123" string S51 = "A 是 123"; // S51的容是 "A是123" string S6(S5) ; // 複製S5的內容,另造一個新物件S6
string S61 = S5; // 複製S5的內容,另造一個新物件S61 string S7(s); // S4的內容由C-style字串s構成
定義String物件 (1/2) string S5("A 是 123"); // S5的內容是 "A是123“ string S8(5, ‘c’); // S8由5個 ‘c’ 字元所構成 string S9(S5, 2); // S9由S5[2]及其後的所有字元 //構成,亦即 "是123"; string S91 (S5, 2, 4); // S91由S5[2]起算,長度為4個字元的 // 部份所構成,亦即 "是1“ string* pS = new string[2]; //動態配置了兩個string物件, // pS指向第一個物件的起頭處
使用下標指定string物件的元素 • S1[0]代表string物件S1的第一個字元。 • S1[1]代表string物件S1的第二個字元。
22.3 字串的更改、清除、剪接與部份複製 (1/5) • (假設S1和S2為兩個先前已定義過的字串物件): S1[2]='G'; // 將S1的第3個字元改成 'G' S1.at(2)=‘G’; // 與S1[2]=‘G’;相同 S2.insert(2,S1);//在S2[2]前插入字串 S1
字串的更改、清除、剪接與部份複製 (2/5) swap(S1,S2); // 將 S1 和 S2 的內容互相交換 S1.swap(S2); // 將 S1 和 S2 的內容互相交換 S1.resize(3); // 只保留 S1[0] 到 S1[2] 共3個字元, // 其餘字元全數清除 S1.resize(5,‘A’); // 如果 S1 原來的字串長度大於 5, // 只保留前 5 個字元,如果原來的字串長度 // 小於 5,則不足之處全補上字元 'A'
字串的更改、清除、剪接與部份複製 (3/5) S2.erase(2); // 清除自S2[2] 起之後的所有字元 S2.erase(2,3); // 清除從S2[2] 起共3個字元 S2.erase(); // 將S2 的內容全部清除 S2.erase(2,5); // 將 S2[2] 到 S2[6]共5個字元清除 S2.replace(2,3,S1); // 將 S2[2] 到 S2[4] 共3個 //字元清除並以 S1 取代
字串的更改、清除、剪接與部份複製 (4/5) S2=S1; // S2 的內容與 S1相同,但兩者為獨立物件 S2.assign(S1); // 與 S2=S1 相同 S2.assign(S1,2,3); // S2的內容為 S1[2]到 S1[4]共3個字元 S2=S1.substr(2); // 將S1[2]及其後的所有內容存到 S2 中 S2=S1.substr(2,3); // 將 S1[2] 到 S1[4] 共3個字元存到 // S2 中,與 S2.assign(S1,2,3) 相同
字串的更改、清除、剪接與部份複製 (5/5) S2.append(S1); // 在 S2 之後串接上 S1 S2.append(S1,2,3); // 在 S2 之後串接上 S1[2] 到 S2[4] // 共3個字元 S3=S1+S2; // S3 的內容改為由 S1 和 S2 串接而成 S2+=S1; // 在 S2 之後串接上 S1
使用begin() 和end() 兩個指標物件直接指定string物件的起頭和結尾處 // 將 S2[2] 到 S2 倒數第4個字元間的內容附加到 S1 之後: S1.append(S2.begin()+2, S2.end()-3); // 將 S2[2] 到 S2 倒數第4個字元間的內容清除:S1.erase(S1.begin()+2, S1.end()-3); // 將 S1 的前3個字元複製到 S2[2] 至 S2[4] 的位置:S1.copy(S2.begin()+2, 3);
範例程式 (字串物件的操作) 檔案ModifyString.cpp // ModifyString.cpp #include <string> #include <iostream> using namespace std; int main() { string S1("0123456789"), S2("abcdefghi"); string S3("必需 do it"), S4, S5 ("長度是 123"); string S6(1,'A'), S7(S3,1,3), S8 (S3, 2, 5); cout << "(1) S3 原來的內容是: " << endl; cout << " " << S3 << endl; cout << " 執行 string S8 (S3, 2, 5); 後\n" << " S8 = " << S8 << endl; cout << "(2) S1 原來的內容是: " << endl; cout << " " << S1 << endl; S1.resize(7); cout << " 執行 S1.resize(7); 後\n " << " S1 = " << S1 << endl; cout << "(3) S5 原來的內容是: " << endl; cout << " " << S5 << endl; S5='A';
cout << " 執行 S5 ='A'; 後\n " << " S5 = " << S5 << endl; cout << "(4) S1 原來的內容是:" << endl; cout << " " << S1 << endl; cout << " S3 原來的內容是:" << endl; cout << " " << S3 << endl; S3.copy(S1.begin()+2,4); cout << " 執行 S3.copy(S1.begin()+2,4) 後." << endl; cout << " S1 的內容是:" << endl; cout << " " << S1 << endl; cout << " S3 的內容是:" << endl; cout << " " << S3 << endl; cout << "(5) S1 原來的內容是:" << endl; cout << " " << S1 << endl; cout << " S3 原來的內容是:" << endl; cout << " " << S3 << endl;
S3=S1.substr(2,5); cout << " 執行 S3=S1.substr(2,5); 後." << endl; cout << " S3 的內容是:" << endl; cout << " " << S3 << endl; cout << "(6) S1 原來的內容是:" << endl; cout << " " << S1 << endl; S1.erase(1,3); cout << " 執行 S1.erase(1,3); 後." << endl; cout << " S1 的內容是:" << endl; cout << " " << S1 << endl; cout << "(7) 執行 S4=S1+S3; 後." << endl; S4=S1+S3; cout << " S4 的內容是:" << endl; cout << " " << S4 << endl; return 0; };
程式執行結果 (1) S3 原來的內容是: 必需 do it 執行stringS8 (S3, 2, 5); 後 S8 = 需 do (2) S1 原來的內容是: 0123456789 執行 S1.resize(7); 後 S1 = 0123456 (3) S5 原來的內容是: 長度是 123 執行 S5 ='A'; 後 S5 = A
(4) S1 原來的內容是: 0123456 S3 原來的內容是: 必需 do it 執行 S3.copy(S1.begin()+2,4) 後. S1 的內容是: 01必需6 S3 的內容是: 必需 do it (5) S1 原來的內容是: 01必需6 S3 原來的內容是: 必需 do it 執行 S3=S1.substr(2,5); 後. S3 的內容是: 必需6
(6) S1 原來的內容是: 01必需6 執行 S1.erase(1,3); 後. S1 的內容是: 0需6 (7) 執行 S4=S1+S3; 後. S4 的內容是: 0需6必需6
22.4 字串之間的比對和比較 (1/2) S1.find(S2); // 在S1中尋找S2的組成字元所在的位置 S1.find(S2,S3); // 由 S1[3]開始尋找 // S2 的組成字元所在的位置 S1.find_first_of(S2); // 在 S1 中尋找第一個吻合// S2 的組成字元所在的位置 S1.find_first_of(S2,3); // 由 S1[3] 開始尋找第一個吻合// S2 的組成字元所在的位置
字串之間的比對和比較 (2/2) //在 S1 中尋找第一個不吻合 S2 的組成字元所在的位置 S1.find_first_not_of(S2); // 在 S1 中尋找最後吻合S2 的組成字元所在的位置 S1.find_last_of(S2); // 在 S1 中尋找最後不吻合 S2 的組成字元所在的位置; S1.find_last_not_of(S2);
字串內容的檢查 S1.size(); // 檢查 S1 內的字元數目 S1.length(); // 與 S1.size(); 相同 S1.empty(); // 檢查 S1是否為空字串,輸出為 // true 或 false
範例程式 檔案 FindSub.cpp • 使用find() 在字串物件 (S1和S2) 中尋找吻合另一個字串物件 (Sub1和Sub2) 的位置。 // FindSub.cpp #include <string> #include <iostream> using namespace std; int main() { string S1="I do not know it at all."; string S2="說真的,我不知道她是否愛我。"; int Site, Length1, Length2, Count; string Sub1 = "no"; string Sub2 = "我"; Length1 = Sub1.size(); Count = 0; Site = 0; cout << "字串 \"" << Sub1 << "\" 位於字串 \"" << S1 << "\" 的位置在:" << endl;
while ((Site = S1.find(Sub1,Site)) !=-1) { cout << Site << " "; Site=Site+Length1; Count++; }; cout << "\n共有 " << Count << " 個 \"" << Sub1 << "\" 在其中." << endl; Length2 = Sub2.size(); Count = 0; Site = 0; cout << "中文字 \"" << Sub2 << "\" 位於字串 \"" << S2 << "\" 的位置在:" << endl; while ((Site = S2.find(Sub2,Site)) !=-1) { cout << Site << " "; Site=Site+Length2; Count++; }; cout << "\n共有 " << Count << " 個 \"" << Sub2 << "\" 在其中." << endl; return 0; }
程式執行結果 (1) 字串 “no" 位於字串 "I do not know it at all." 的位置在: 5 10 共有 2 個 "no" 在其中. (2) 中文字 "我" 位於字串 "說真的,我不知道她是否愛我。" 的位置在: 8 24 共有 2 個 "我" 在其中
字串之間的比較 • 字串由char構成,依照ASSII碼的編號方式可以比較大小。 • 字串有兩種比較方式: (1)使用重載運算子, (2)使用成員函數 compare()
使用重載運算子比較字串 S1 = S2+S3; // 將 S2 和 S3 串接合併,存入 S1 S1 += S2; // S1 的尾端串接了 S2 的內容 cout << S1; // 將 S1 透過資料流輸出 cin >> S2; // 透過資料流將資料輸入 S2 內其中 //cin >> S2; 可以寫成 //getline(cin,S2);
使用成員函數Compare() • 指令 S1.compare(S2); 的輸出值有 1、0和 -1三種: 1 如果 S1 > S2 0 如果 S1 = S2 -1 如果 S1 < S2
範例程式 檔案 StringBubble.cpp • 改寫10.6節的範例程式Bubble.cpp,使用比較大小的運算子「>」將字串依照字典的次序排列。 還運用了22.3節介紹的字串成員函數swap() 代替原來自行定義的樣版函數Exchange() 以互相交換字串的內容。
// StringBubble.cpp #include <string> #include <iostream> using namespace std; // --- 定義樣版函數 Bubble() ------------------- template <class T> void Bubble(T * const V, int N ) { for (int i=0; i<N; i++) for (int j=N-1; j>i; j--) if (V[j]<V[j-1]) swap(V[j],V[j-1]); return; }
// ---- 主程式 --------------------------------- int main() { const int Size = 5; int i; string Students[Size]= {"Nancy","Lulu", "Margaret","Stephanie","Monica"}; cout << "\n執行 Bubble() 之前, Data 的值是:" << endl; for (i=0; i<Size; i++) cout << "(" << i+1 << ") " << Students[i] << endl; Bubble(Students, Size); cout << "\n執行 Bubble() 之後, Data 的值是:" << endl; for (int i=0; i<Size; i++) cout << "(" << i+1 << ") " << Students[i] << endl; return 0; }
程式執行結果 執行 Bubble() 之前,Data 的值是: (1) Nancy (2) Lulu (3) Margaret (4) Stephanie (5) Monica 執行 Bubble() 之後,Data 的值是: (1) Lulu (2) Margaret (3) Monica (4) Nancy (5) Stephanie
使用C_str() 成員函數將字串物件轉換為C-style字串 • 使用資料型態為「const char *」的指標pSc,以代表 C-style 字串: string S1("FileName"); const char* pSc; pSc = S1.c_str(); • 這時pSc只是指向原先S1物件內字元陣列的指標,並沒有另外複製產生新的字串。
c_str() 的轉換結果屬於資料型態「const char *」 • S1.c_str()無法直接由「char *」的指標接收: char* pS2; // pS2 為 「char *」的指標 pS2 = S1.c_str(); // 錯誤!
將字串物件的內容複製到字元陣列char [] string S1("FileName"); char CS[10]; strcpy(CS, S1.c_str());
使用strcpy() 將S1的內容複製到字元陣列指標「char *」 • 指標所代表的位置必需有夠的空間: stringS1("FileName"); char* pS = new char[S1.length()+1]; strcpy(pS, S1.c_str());
使用data() 成員函數將字串物件轉換為C-style字串 stringS2("abcdefghi"); const char* pSc; pSc = S2.data(); • 這個語法並沒有另外複製產生新的字串。
將C-style字串轉換為string物件 string S3, S4; char CS2[20] = "Hello! 您好!"; char* pS2 = "早安!"; S3 = CS2; // 「=」在string類別中已正確重載過 S4 = pS2; • 此時S3和S4為複製產生的新字串物件。
範例程式 檔案 CString.cpp • 示範和驗證字串物件和C-style string之間的轉換。