Ch10 字串處理

搭配green judge解題系統
Special thanks to 台中女中sagit老師 <(_ _)>

上一章:陣列
下一章:大數運算
回目錄:國立科學園區實驗中學C++程式語言自學講義

字串與陣列的關聯性

所謂的字串,就是我們剛上高一的第一堂cout課學過的「一串英文字」
例如當時練習過的

cout << "Hello!" << endl;
cout << "Bang!" << endl;

介於cout與endl中間的那個,
用雙引號圍起來的部分,就是「字串」
顧名思義就是「一串字」

我們在「其他資料型態」的單元中
也學過要怎麼宣告一個字串
底下的例子幫大家回憶一下

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格
程式就要當掉拉~!!一定要小心

修改字串中的字

剛才提到的s[0]啦、s[5]啦
他們就是在第七章所提到的「字元」
也就是「一個字母」
所以當你想要把一個字串裡的其中一個字改掉的時候
必須使用單引號的「字元」喔
例如

string s; s = "Hello"; s[0] = 'D'; cout << s ;

這樣一來就會在小黑窗上看到 "Dello"

string s; s = "Hello"; s[4] = 'q'; cout << s ;

就會在小黑窗上看到 "Hellq"

取得字串長度

那我們要怎麼知道一個字串長度有多少呢?
雖然可以目測出Hello長度是5
(記得,長度是5,代表編號是0~4喔)
但如果字串是來自使用者的輸入
那就沒辦法預先知道字串長度了

以下示範如何取得一個字串的長度

string s; cin >> s; int slen; //用這個變數來儲存s的長度吧 slen = s.length(); //取得s的長度,存在slen這個變數裡

要取得s的長度,就在s的後面加上.length()就好
至於為何是這樣寫,說來話長,有興趣的可以發問
不過我們就先學會他的寫法就好了~!!

要印出字串的內容
除了直接cout << s之外
也可以一個字一個字印
例如

string s; cin >> s; int i; int slen = s.length(); for(i=0; i<slen; i++){ cout << s[i]; }

當然也可以倒過來印
把使用者輸入的Hello變成olleH

string s; cin >> s; int i; int slen = s.length(); for(i=slen-1; i>=0; i--){ cout << s[i]; }

就像陣列一樣,如果要從最後一個往前印回來
記得最後一個的編號是「長度-1」
然後每次將i往前推一格,直到0為止
就可以將內容從最後一格印回前一格了

【學生練習題】

應用:迴文

有關程式語法都學得差不多囉
接下來介紹一些應用的小技巧

迴文的定義就是「正著看反著看都一樣」
例如:
上海自來水來自海上、
花蓮噴水池水噴蓮花、
我愛你愛我、
ABCDCBA、
等等

一個句子他究竟是不是迴文
我們可以利用迴圈來檢驗

以下示範確認一個字串是不是迴文的程式
首先先將字串讀進來,並且取得他的長度

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的話,就代表是通通等於

int n=0; int i; for(i=0;i<=len-1;i++){ //每一個字都看一看 if(s[i]!=s[len-1-i]) n=n+1; //是否和他對應位置的字一樣 }

最後決定輸出YES或是NO

if(n==0) cout<<"YES"; else cout<<"NO";

【學生練習題】

應用:字元比對

先來看看這題吧

【學生練習題】

【本題解說】

輸入兩個字串,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

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++上面之後
把_____改成你認為正確的程式
當然,如果你不要複製這份去改,而是自己從頭到尾寫,那更好喔!!

應用:字元處理

我們在第七章中有教過
如果把字元拿去加上一個數字,就會變成那個英文字母往後數幾個字的樣子
例如

char ch = 'a' ; ch = ch + 3 ; cout << ch ;

會看到一個d

char ch = 'A' ; ch = ch + 1 ; cout << ch ;

會看到一個B

如果要把整個字串裡面的每個字母都向後移一位
可以利用迴圈做

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判斷

cin >> s; for(i=0;i<s.length();i++){ if(s[i]=='Z') s[i]='A'; else s[i]=s[i]+1; } cout << s;

【學生練習題】

提示:這題因為是要往前移兩格,且A要變成Y,B要變成Z

應用:字元轉數字、字串轉數字

先來試試看這段程式

string s = "0123"; int n = s[0]; cout<<n;

s的第0位,應該是'0'這個字
沒想到居然印出了48
發生什麼事?

每一個字元它背後都有個數字代碼
下面這張圖列出了所有的英文字母和數字以及它的代碼

左邊是字元
右邊是他的代碼
找到'0'了嗎,可以看到他旁邊的代碼是48

以此類推
'1'的代碼則是49
'2'的代碼則是50
一直到'9'的代碼是57

【例題】

輸入一個字串
輸出字串中所有的數字
例如輸入1ab5cd568eqq4qq
則輸出155684

既然是數字,那麼它的代碼應該會介於'0''9'之間

string s; cin >> s; for(int i=0;i<s.length();i++){ if(s[i]<='9' && s[i]>='0') cout<<s[i]; }

【例題】

輸入一個字串
保證字串裡每個字元都是數字
輸出每個數字相加後的結果

要把所有數字相加
先想想看"01"這個字串相加後應該要是多少
應該要是1沒錯吧!
但如果把它代碼直接拿來相加會得到 48+49=97
可真不妙

在把它拿來做運算之前
應該要先讓它等於它符號所代表的數字
也就是看到'0'應該要加上數字0
看到'1'應該要加上數字1

既然想要數字
將字元減掉'0'就可以得到他所代表的數字了
像是
'1'-'0' = 1
'5'-'0' = 5
以此類推

string s; cin >> s; int ans=0; for(int i=0;i<s.length();i++){ ans+=(s[i]-'0'); } cout<<ans;

應用:整行輸入

cin有個很大的特點,就是會用使用者在小黑窗上輸入的空白鍵以及enter來當成結束的依據
例如程式中有cin>>s1; cin>>s2;
而小黑窗上打 hello world
那麼hello就會被存進s1裡
world會被存進s2裡

但如果希望將整個"hello world"存進s1裡面
該怎麼辦呢?

可以把原本的 cin>>s1
改成 getline(cin, s1)
這麼一來,就只有enter會被當成結束的依據
你不管打了多少空白鍵,他都會當成字串的一部份喔!

【例題】

輸入兩個字串,s1與s2
其中都有可能出現空白鍵
請先輸出s2
再輸出s1
例如s1是 hello world
s2是 saint dodo bang
那麼請輸出
saint dodo bang
hello wolrd

參考範例如下

string s1, s2; getline(cin, s1); getline(cin, s2); cout << s2 << endl; cout << s1 << endl;

【學生練習題】

上一章:陣列
下一章:大數運算
回目錄:國立科學園區實驗中學C++程式語言自學講義