知識網路1.5 將字串中的小寫字母轉換成大寫
以下是本節涉及的知識點:
- 將字串小寫字母轉成大寫
- 字元陣列
- 從鍵盤輸入字串
char
型資料的特點- 庫函式
我們終於來到了這一系列boss中最後的boss了。雖然是最後一個,但卻比前面的都要簡單,因為這裡面沒有複雜的多重迴圈,沒有燒腦的找規律,有的只是簡單平和的數值處理。雖然比較簡單,但是這裡面講述的方法和思路也是可以拓展的,是走向更高階的字串處理的基石。
我們從這裡學習了小寫字母轉換成大寫後,就自然會明白如何轉換成小寫,如何把整數字符串轉換成整數等等。
利用if或者switch進行大小寫轉換可行嗎?
(這是反例,小孩子請勿模仿)說到大小寫轉換,我們最容易想到的就是如下程式碼:
char c= 'c';
if(c=='a')c='A';
else if(c=='b')c='B';
else if(c=='c')c='C';
......
else if(c=='z')c='Z';
可能覺得寫很多個if
不太方便,所以我們用switch
來做:
char c='c';
switch(c){
case 'a':
c='A';
break;
case 'b':
c='B';
break;
case 'c':
c='C';
break;
......
case 'z':
c='Z';
break;
}
這樣做當然是可以的,但是太笨了,讓我們的程式碼顯過於冗長而且沒有必要。
我們需要找到大小寫轉換之間的規律
(這個考點的頻率比較低,覺得難可以放棄)
要知道,在計算機裡面,每個字元實際上都是用數字儲存的,每個字母都對應了一個數字(ASCII碼錶)。雖然我們不用記憶這張表的內容,但仍需要了解,字母在這張表裡面是相鄰的。也就是說,我們可以通過運算來改變字元的內容。比如我們用'A'+1
就可以得到'B'
。再比如說,我們可以用'B'-'A'
得到A
B
兩個字母在字母表上的位置關係,運算的結果是1
,也就是說B
是A
的後1
個字母。
(ASCII碼錶、相關具體的數值都不是考點
a
在大寫的A
後面32
個,也就是說'a'-'A'
的值是32
。那麼也就是說,'b'-'B'
,'c'-'C'
的值都是32
。也就是說,'a'-'A'=32
,那麼我們做一個簡單的代數變換,得到'a'-32='A'
。
(再強調一次,32不是考點,不要背)
由此我們得到了一個神奇的公式,對於任何一個小寫字母字元,減去32
就能將其轉換成大寫。也就是說,對於char
型變數c
,只要c
記憶體放的是小寫字母,c-32
就能將其轉換為對應的大寫字母。(同理,只要對大寫字母加上32
也就會變成小寫字母)
但是我們並不記得32
這個數字怎麼辦?還記得32
是怎麼來的嗎?32
是由'a'-'A'
得到的。後者也是字面值常量,所以可以直接寫。也就是說,我們寫c-32
可以,寫c-('a'-'A')
也可以,把小括號開啟,就得到c-'a'+'A'
。
發現什麼規律了沒?c-'a'+'A'
這個式子,也可以理解為是字元c
在小寫字母表裡面的順序(就是c-'a'
),變換到大寫字母表裡面(就是+'A'
)的結果。
將字串裡面的小寫字母轉換為大寫字母
有了上述基礎知識鋪墊之後,我們解決這個問題就要簡單很多了。首先還是從一個情景展開討論:
從鍵盤輸入一串字串,我們只會輸入英文半形字元,可能字母和非字母是混在一起的,但最多不會超過N個字元(假定N=200)。我們將輸入的字串中的小寫字母轉換為大寫字母,不是小寫字母的就保持原樣,輸出轉換後的結果。
我們將這個情景分解為如下步驟:
- 定義常量和字元陣列
- 從鍵盤輸入字串
- 對字串裡面的字元逐個小寫轉大寫操作
- 輸出轉換後的字串
定義常量和字元陣列
首先,從最基本的工作做起:
#include<iostream>
using namespace std;
int main(){
const int N=200;
char a[N];
}
從cin輸入字串
下面需要從鍵盤輸入字串。我們要用上cin
。字串的輸入不像數字陣列那樣需要一個一個輸入,我們直接使用如下語句就能實現輸入字串(注意我們直接用的陣列名字):
cin>>a;
要注意的是,我們字元陣列最大僅有200
。根據題設我們知道輸入不會超過200
這個限制。但是我們卻並不知道使用者到底輸入了多長的字串,可能只輸入了長度為5
的字串,後面的195
的空間都是空著的。不過這點空間浪費並不重要。
另外一個需要注意的點是,cin
使用任何空格、換行之類的作為輸入分隔,所以此處輸入的字串不能含有空格。如果想要包含空格的話,可以使用如下語句**(看到了知道是什麼即可,不需要會用)**:
cin.getline(a, N);
這個語句能一次讀取一行,其中a
是陣列名,N
是字元陣列的最大大小。
對某個字元進行小寫轉大寫
下面是對字串裡面的字元逐個小寫轉大寫。首先,針對字串裡面的下標為i
的字元,若其為小寫,我們用下面這一語句就可以將其轉換為大寫:
a[i]=a[i]-'a'+'A';
我們也可以簡寫為下面的形式:
a[i]-='a'-'A';
判斷是否是小寫字母
但我們要如何判斷a[i]
是否是小寫字元呢?我們把字元想成數字就可以了。小寫字母一定在'a'
到'z'
的範圍之內,也就是說小寫字母一定滿足這個條件:a[i]>='a' && a[i]<='z'
。其中&&
是我們還沒講過的“和”運算子,表示當它左邊和右邊的表示式都同時成立(為真)的時候,整個表示式才成立。於是加上前面的,我們就能實現將小寫字母轉換為大寫:
if(a[i]>='a' && a[i]<='z')
a[i]-='a'-'A';
對字串每個字元進行迴圈
接下來我們只要對字串中的每個元素都執行下述操作就可以了。
但是現在問題來了,我們並不知道字串的具體長度是多少,常量N
只是指示了字串的最大長度,卻並不表示其實際長度。我們如果對後面空著的空間操作的話,可能會發生未知錯誤。
如何能知道字串的實際長度呢?事實上,一個字串,無論其佔用空間多少,它總是以'\0'
結尾。也就是說,'\0'
就是字串結束的標誌,我們只要發現字串其中有一個字元是'\0'
,則表示字串已經結束了,其後面的內容都是無效的。
由此,我們有改進版的for
迴圈:
for(int i=0; a[i]!='\0'; i++)
if(a[i]>='a' && a[i]<='z')
a[i]-='a'-'A';
上述for
迴圈的迴圈條件是:只要a[i]
不是'\0'
,就繼續迴圈。
最後是輸出
輸出也可以直接用字元陣列的名字:
cout<<a;
小結
總結一下,我們總共寫了些什麼:
#include<iostream>
using namespace std;
int main(){
//定義常量和陣列
const int N=200;
char a[N];
//輸入一行
cin.getline(a, N);
//對於字串的每個字元
for(int i=0; a[i]!='\0'; i++)
//若是小寫字母
if(a[i]>='a' && a[i]<='z')
//就將其轉換為大寫字母
a[i]-='a'-'A';
//輸出字串
cout<<a;
}
參見附件知識網路1.5.1
,執行一下看看結果。
我們可以發現只有小寫字母被轉換為大寫了,大寫字母和各種符號都沒有變化。
庫函式
非考點。
這麼常用的操作,肯定會有前人為我們做好相關的工作,我們只需要簡單寫個語句之類的就能搞定。
庫函式是指C++預先為我們寫好的程式碼,我們只要用某些語句就能實現這一功能。
比如把一個字元c
(而不是字串)轉換成大寫可以用c=toupper(c)
,而且它會自動判斷是不是小寫字母。
庫函式還有很多,與字串相關的庫函式,要考的我會在第八課裡面詳細講解。