# Ch10 字串處理 > 搭配[green judge解題系統](http://www.tcgs.tc.edu.tw:1218/) > Special thanks to [台中女中sagit老師](http://www.tcgs.tc.edu.tw/~sagit/index.htm) \<\(\_ \_\)\> ## > 上一章:[陣列](https://hackmd.io/s/HJMbs-ARW) > 下一章:[大數運算](https://hackmd.io/s/r1KtmuMdf) > 回目錄:[國立科學園區實驗中學C++程式語言自學講義](https://hackmd.io/s/B18yT_i5Z) ## <font color='darkblue'>字串與陣列的關聯性</font> 所謂的字串,就是我們剛上高一的第一堂cout課學過的「一串英文字」 例如當時練習過的 ```cpp cout << "Hello!" << endl; cout << "Bang!" << endl; ``` 介於cout與endl中間的那個, 用雙引號圍起來的部分,就是「字串」 顧名思義就是「一串字」 我們在「其他資料型態」的單元中 也學過要怎麼宣告一個字串 底下的例子幫大家回憶一下 ```cpp string s = "Hello!" ``` 其中s就是這個變數的名稱, 所以不管是`cout << "Hello!"`還是`cout << s` 都可以在小黑窗上看到Hello的字樣 字串歸字串,為什麼要提陣列呢? 還記得陣列相當於一串變數 例如int a[5],代表的就是5個整數 假設這五個整數分別是{1,3,5,2,4}的話 `cout << a[0]`會在小黑窗上看到1 `cout << a[4]`會在小黑窗上看到4 其實,字串也有類似的功能喔! 像剛才的`string s = "Hello!"` 如果接上`cout << s[0]`的話 就會在小黑窗上看到一個H,也就是s這個字串的第0個字 如果接上`cout << s[5]`的話 就會在小黑窗上看到一個!,也就是s這個字串的第5個字 當然,如果要`cout << s[6]`或是`cout << s[100]`的話 由於s這個字串根本沒有第6格也沒有第100格 程式就要當掉拉~!!一定要小心 ## <font color='darkblue'>修改字串中的字</font> 剛才提到的s[0]啦、s[5]啦 他們就是在第七章所提到的「字元」 也就是「一個字母」 所以當你想要把一個字串裡的其中一個字改掉的時候 必須使用**單引號**的「字元」喔 例如 ```cpp= string s; s = "Hello"; s[0] = 'D'; cout << s ; ``` 這樣一來就會在小黑窗上看到 "Dello" ```cpp= string s; s = "Hello"; s[4] = 'q'; cout << s ; ``` 就會在小黑窗上看到 "Hellq" ## <font color='darkblue'>取得字串長度</font> 那我們要怎麼知道一個字串長度有多少呢? 雖然可以目測出Hello長度是5 (記得,長度是5,代表編號是0~4喔) 但如果字串是來自使用者的輸入 那就沒辦法預先知道字串長度了 以下示範如何取得一個字串的長度 ```cpp= string s; cin >> s; int slen; //用這個變數來儲存s的長度吧 slen = s.length(); //取得s的長度,存在slen這個變數裡 ``` 要取得s的長度,就在s的後面加上`.length()`就好 至於為何是這樣寫,說來話長,有興趣的可以發問 不過我們就先學會他的寫法就好了~!! 要印出字串的內容 除了直接`cout << s`之外 也可以一個字一個字印 例如 ```cpp= string s; cin >> s; int i; int slen = s.length(); for(i=0; i<slen; i++){ cout << s[i]; } ``` 當然也可以倒過來印 把使用者輸入的Hello變成olleH ```cpp= string s; cin >> s; int i; int slen = s.length(); for(i=slen-1; i>=0; i--){ cout << s[i]; } ``` 就像陣列一樣,如果要從最後一個往前印回來 記得最後一個的編號是「長度-1」 然後每次將i往前推一格,直到0為止 就可以將內容從最後一格印回前一格了 > <font color="darkgreen"> 【學生練習題】</font> > - [ ] [Green Judge b007: 倒背如流 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b007) ## <font color='darkblue'>應用:迴文</font> 有關程式語法都學得差不多囉 接下來介紹一些應用的小技巧 迴文的定義就是「正著看反著看都一樣」 例如: 上海自來水來自海上、 花蓮噴水池水噴蓮花、 我愛你愛我、 ABCDCBA、 等等 一個句子他究竟是不是迴文 我們可以利用迴圈來檢驗 以下示範確認一個字串是不是迴文的程式 首先先將字串讀進來,並且取得他的長度 ```cpp= string s; cin >> s; int len; len=s.length(); ``` 接下來依序檢查: 第0個字有沒有等於第len-1個字? 第1個字有沒有等於第len-2個字? 第2個字有沒有等於第len-3個字? ... 第i個字有沒有等於第len-1-i個字? ... 第len-1個字有沒有等於第0個字? 如果通通等於的話,那就是迴文 否則就不是 我們有很多方法可以檢查是不是通通等於 這邊示範其中一種方法: 我們可以用一個變數來紀錄「有幾次不等於」 如果最後這個變數是0的話,就代表是通通等於 ```cpp=5 int n=0; int i; for(i=0;i<=len-1;i++){ //每一個字都看一看 if(s[i]!=s[len-1-i]) n=n+1; //是否和他對應位置的字一樣 } ``` 最後決定輸出YES或是NO ```cpp=10 if(n==0) cout<<"YES"; else cout<<"NO"; ``` > <font color="darkgreen"> 【學生練習題】</font> > - [ ] [Green Judge b008: 迴文 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b008) ## <font color='darkblue'>應用:字元比對</font> 先來看看這題吧 > <font color="darkgreen"> 【學生練習題】</font> > - [ ] [Green Judge bb009: 無限猴子定理 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b009) <font color='darkorange'>【本題解說】</font> > 輸入兩個字串,s1與s2 > 如果s1中的每個字元都依照順序出現在s2中 > 例如s1是ABC而s2是ccAxoxoBqqqC+++ > 或者s1是123而s2是12345 > 則輸出YES > 否則輸出NO 這題要注意的有3點 1. s1的每個字都是「依序」出現在s2裡嗎?如果s1是ABC,s2是BQAQC,那就是不行的 2. s1如果有重複的字,不能漏算喔,例如如果s1是ABBC,s2是AQBQC,那也是不行的 3. 承上,如果s1是AAAAA,s2是AA,那也是不行的 這題可以這樣做 1.先找出s1[0]出現在s2的哪裡 - 如果找到了,紀錄一下是出現在哪裡,例如是s2[j]==s1[0],那麼就記錄個current=j+1,並且離開迴圈別再找了 2.再來要找的是s1[1]出現在s2的哪裡,且不能比s1[0]還要前面,所以要從current的位置開始找 - 如果找到了,紀錄一下是出現在哪裡,再把current改成它的位置+1,讓下一個要找的從current開始,並且離開迴圈別再找了 - 接下來都以此類推,直到s1裡面的所有字都被找到為止 3.想知道「s1裡所有的字是不是都有被找到」,那就用一個變數紀錄總共有幾個字被找到了,如果最後這個變數正好等於s1的長度,那就代表所有字都有找到(YES),否則就是NO ```cpp= int i, j; int current = 0; int found=0; for(i=0;i<s1.length();i++){ for(j=current;j<s2.length();j++){ if(s2[j]==s1[i]){ current=_____; //下次要從哪裡開始? found++; break; //既然找到了就別再找了 } } } if(found==s1.length()){ cout<<_____ } else{ cout<<_____ } ``` 這份程式碼可以給同學當填充題寫寫看喔 請複製到Dev C++上面之後 把\_\_\_\_\_改成你認為正確的程式 當然,如果你不要複製這份去改,而是自己從頭到尾寫,那更好喔!! ## <font color='darkblue'>應用:字元處理</font> 我們在第七章中有教過 如果把字元拿去加上一個數字,就會變成那個英文字母往後數幾個字的樣子 例如 ```cpp= char ch = 'a' ; ch = ch + 3 ; cout << ch ; ``` 會看到一個d ```cpp= char ch = 'A' ; ch = ch + 1 ; cout << ch ; ``` 會看到一個B 如果要把整個字串裡面的每個字母都向後移一位 可以利用迴圈做 ```cpp= cin >> s; for(i=0;i<s.length();i++){ s[i]=s[i]+1; } cout << s; ``` 這樣如果輸入的是ABC,就會看到BCD 如果輸入的是BANG,就會看到CBOH 但如果輸入Z就會出問題啦,因為Z+1並不是A,而是 \[ 這個符號(左方括弧) 所以如果要讓Z變成A 要在迴圈裡多加一個if else判斷 ```cpp= cin >> s; for(i=0;i<s.length();i++){ if(s[i]=='Z') s[i]='A'; else s[i]=s[i]+1; } cout << s; ``` > <font color="darkgreen"> 【學生練習題】</font> > - [ ] [Green Judge b010: 編碼破解 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b010) 提示:這題因為是要往前移兩格,且A要變成Y,B要變成Z ## <font color='darkblue'>應用:字元轉數字、字串轉數字</font> 先來試試看這段程式 ```cpp= string s = "0123"; int n = s[0]; cout<<n; ``` s的第0位,應該是`'0'`這個字 沒想到居然印出了48 發生什麼事? 每一個字元它背後都有個數字代碼 下面這張圖列出了所有的英文字母和數字以及它的代碼 ![](https://i.imgur.com/YJEbJ7Y.png) 左邊是字元 右邊是他的代碼 找到`'0'`了嗎,可以看到他旁邊的代碼是48 以此類推 `'1'`的代碼則是49 `'2'`的代碼則是50 一直到`'9'`的代碼是57 <font color='darkorange'>【例題】</font> > 輸入一個字串 > 輸出字串中所有的數字 > 例如輸入1ab5cd568eqq4qq > 則輸出155684 既然是數字,那麼它的代碼應該會介於`'0'`到`'9'`之間 ```cpp= string s; cin >> s; for(int i=0;i<s.length();i++){ if(s[i]<='9' && s[i]>='0') cout<<s[i]; } ``` <font color='darkorange'>【例題】</font> > 輸入一個字串 > 保證字串裡每個字元都是數字 > 輸出每個數字相加後的結果 要把所有數字相加 先想想看`"01"`這個字串相加後應該要是多少 應該要是1沒錯吧! 但如果把它代碼直接拿來相加會得到 48+49=97 可真不妙 在把它拿來做運算之前 應該要先讓它等於它符號所代表的數字 也就是看到`'0'`應該要加上數字0 看到`'1'`應該要加上數字1 既然想要數字 將字元減掉`'0'`就可以得到他所代表的數字了 像是 `'1'-'0' = 1` `'5'-'0' = 5` 以此類推 ```cpp= string s; cin >> s; int ans=0; for(int i=0;i<s.length();i++){ ans+=(s[i]-'0'); } cout<<ans; ``` ## <font color='darkblue'>應用:整行輸入</font> cin有個很大的特點,就是會用使用者在小黑窗上輸入的空白鍵以及enter來當成結束的依據 例如程式中有`cin>>s1; cin>>s2;` 而小黑窗上打 `hello world` 那麼hello就會被存進s1裡 world會被存進s2裡 但如果希望將整個"hello world"存進s1裡面 該怎麼辦呢? 可以把原本的 `cin>>s1` 改成 `getline(cin, s1)` 這麼一來,就只有enter會被當成結束的依據 你不管打了多少空白鍵,他都會當成字串的一部份喔! <font color='darkorange'>【例題】</font> > 輸入兩個字串,s1與s2 > 其中都有可能出現空白鍵 > 請先輸出s2 > 再輸出s1 > 例如s1是 hello world > s2是 saint dodo bang > 那麼請輸出 > saint dodo bang > hello wolrd 參考範例如下 ```cpp= string s1, s2; getline(cin, s1); getline(cin, s2); cout << s2 << endl; cout << s1 << endl; ``` > <font color="darkgreen"> 【學生練習題】</font> > - [ ] [Green Judge b013: 評語重排 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=b013) ## > 上一章:[陣列](https://hackmd.io/s/HJMbs-ARW) > 下一章:[大數運算](https://hackmd.io/s/r1KtmuMdf) > 回目錄:[國立科學園區實驗中學C++程式語言自學講義](https://hackmd.io/s/B18yT_i5Z)