1. 程式人生 > >知識網路1.5 將字串中的小寫字母轉換成大寫

知識網路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,也就是說BA的後1個字母。

ASCII碼錶、相關具體的數值都不是考點

)那麼我們需要做大小寫轉換的話,就可以先找到大小寫字母之間的差值,在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)。我們將輸入的字串中的小寫字母轉換為大寫字母不是小寫字母的就保持原樣輸出轉換後的結果。

我們將這個情景分解為如下步驟:

  1. 定義常量和字元陣列
  2. 從鍵盤輸入字串
  3. 對字串裡面的字元逐個小寫轉大寫操作
  4. 輸出轉換後的字串

定義常量和字元陣列

首先,從最基本的工作做起:

#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),而且它會自動判斷是不是小寫字母。 庫函式還有很多,與字串相關的庫函式,要考的我會在第八課裡面詳細講解。