C言語のきほん|文字を変換する(toupper、tolower)

大文字と小文字を思いどおりに変える。toupper と tolower で文字変換の基本をやさしく身につけよう

C言語で文字を扱っていると、「小文字を大文字にそろえたい」「大文字を小文字に変えたい」といった場面がよくあります。
たとえば、ユーザーが入力した英字を見やすく整えたり、大文字と小文字の違いをそろえて比較しやすくしたり、表示用の文字列を整形したりするときです。

こうしたときに役立つのが、文字を変換する関数である toupper と tolower です。

  • toupper は、小文字を大文字に変換する関数
  • tolower は、大文字を小文字に変換する関数

どちらも ctype.h に用意されている標準ライブラリ関数で、文字コードの並び方を自分で意識しなくても、安全に文字変換を行えるのが大きな特徴です。

たとえば、C言語を学び始めたころには、

if (c >= 'a' && c <= 'z') {
    c = c - ('a' - 'A');
}

のように、自分で文字コードの差を使って変換を書くこともできます。
でも、この方法は文字コードの並び方に依存した書き方です。
それに対して toupper や tolower を使えば、「英小文字なら大文字にする」「英大文字なら小文字にする」という意図を、そのままシンプルに書けます。

さらに便利なのは、英字以外の文字はそのまま返すという点です。
つまり、数字や記号、空白などに対して無理に変換しようとせず、必要な文字だけを自然に変換してくれます。

この節では、toupper と tolower の基本的な使い方に加えて、

  • どのような文字が変換されるのか
  • 変換されない文字はどうなるのか
  • getchar と組み合わせて1文字ずつ変換する方法
  • 文字列全体を順番に変換する考え方
  • 実践問題としてどのように応用できるのか

まで、順番にていねいに見ていきます。

文字変換の関数はとてもシンプルですが、入力チェックや文字列整形の基本としてとても大切です。
ここでしっかり身につけておくと、あとで文字列比較や文字列処理をするときにも役立ちます。

文字を変換する関数とは

文字を変換する関数とは、入力された文字が英字であれば、その大文字・小文字を変換して返す関数です。

今回扱うのは次の2つです。

関数名役割
toupper英小文字を英大文字に変換する
tolower英大文字を英小文字に変換する

たとえば、

入力toupper の結果tolower の結果
aAa
BBb
555
%%%

この表からわかるように、英字以外の文字は変換されず、そのまま返されます。

この性質のおかげで、文字を1つずつ順番に調べながら変換したいときでも、「英字かどうかを毎回自分で細かく判定してから変換する」手間を減らしやすくなります。

toupper 関数とは

toupper は、英小文字を英大文字に変換する関数です。

関数宣言

#include <ctype.h>

int toupper(int c);

機能

引数 c が英小文字なら、対応する英大文字に変換して返します。
それ以外の文字なら、そのまま返します。

返却値

条件返却値
英小文字対応する英大文字
それ以外入力された文字そのもの

使用例

int c = 'a';
c = toupper(c);

この場合、c には A が入ります。

tolower 関数とは

tolower は、英大文字を英小文字に変換する関数です。

関数宣言

#include <ctype.h>

int tolower(int c);

機能

引数 c が英大文字なら、対応する英小文字に変換して返します。
それ以外の文字なら、そのまま返します。

返却値

条件返却値
英大文字対応する英小文字
それ以外入力された文字そのもの

使用例

int c = 'Z';
c = tolower(c);

この場合、c には z が入ります。

なぜ int 型を使うのか

toupper や tolower の引数と返却値は int 型です。
これは getchar などの文字入力関数と同じく、EOF のような特別な値を扱いやすくするためでもあります。

学習の初期では、英字を変換するときに

char ch;

のように char 型で扱うこともありますが、getchar と組み合わせるなら int 型を使うのが基本です。

たとえば、

int c;
c = getchar();
c = toupper(c);

のように書くと、EOF の扱いも含めて自然に処理できます。

どんな文字が変換されるのか

toupper と tolower は、英字だけを対象に変換します。
数字や記号、空白文字などは変換しません。

入力文字touppertolower説明
aAa小文字なので大文字化できる
mMm小文字なので大文字化できる
AAa大文字なので小文字化できる
ZZz大文字なので小文字化できる
777数字なので変化しない
%%%記号なので変化しない
空白空白空白空白なので変化しない

この「英字以外はそのまま」という性質はとても便利です。
たとえば、文字列全体を順番に変換するとき、数字や記号が混ざっていても安心して処理できます。

この図では、入力文字に対して toupper と tolower がどのように働くかをまとめています。
英字は大文字・小文字に応じて変換されますが、数字や記号はそのまま返されることがわかります。
この性質を理解しておくと、文字列全体をまとめて処理するときにも安心して使えます。

シンプルなプログラム例

キーボードから文字を繰り返し入力し、小文字なら大文字に変換して表示するプログラムです。

ファイル名:12_9_1.c

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    int c;

    printf("文字を続けて入力してください。(終了条件:Ctrl+Z または Ctrl+D)\n");

    while ((c = getchar()) != EOF) {
        /* 改行文字は表示しない */
        if (c == '\n') {
            continue;
        }

        /* 小文字を大文字に変換する */
        c = toupper(c);

        printf("変換後の文字: %c\n", c);
    }

    return 0;
}

このプログラムのポイント

このプログラムでは、getchar で1文字ずつ入力を受け取り、それを toupper に渡しています。

特に大事なのは次の2点です。

getchar の返り値を int 型で受けている

int c;

としています。
これは EOF を正しく扱うためです。

改行文字をスキップしている

if (c == '\n') {
    continue;
}

getchar は Enter キーによる改行文字も読み込みます。
そのまま変換してしまうと見づらくなるので、この例では改行を表示対象から外しています。

実行イメージ

たとえば、次のように入力したとします。

a
B
5
%

すると、表示は次のようになります。

変換後の文字: A
変換後の文字: B
変換後の文字: 5
変換後の文字: %

この結果からも、toupper は小文字だけを大文字に変換し、それ以外はそのまま返していることがわかります。

文字列全体を変換する考え方

toupper や tolower は1文字単位の関数です。
そのため、文字列全体を変換したいときは、文字列を先頭から順番に1文字ずつ見ていきます。

たとえば、文字列 Hello を全部大文字にしたいなら、

  • H を変換する
  • e を変換する
  • l を変換する
  • l を変換する
  • o を変換する
  • \0 で終了する

という流れになります。

つまり、配列を順番にたどりながら、それぞれに toupper や tolower を適用していくわけです。

toupper と tolower の使い分け

この2つの関数は、役割が反対です。

目的使う関数
小文字を大文字にそろえるtoupper
大文字を小文字にそろえるtolower

たとえば、すべて大文字で表示したいなら toupper を使います。
逆に、入力された英字をすべて小文字に統一したいなら tolower が向いています。

実践問題

Ctrl + Z(UNIX/Linux では Ctrl + D)が入力されるまで文字を連続して入力し、
英大文字、英小文字、数字、記号の個数を数えて表示するプログラムを作成してください。
ただし、空白類文字は数えないものとします。

解答例

ファイル名:12_9_2.c

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    int c;
    int upper_count = 0;
    int lower_count = 0;
    int digit_count = 0;
    int symbol_count = 0;

    printf("文字を入力してください。(終了条件:Ctrl+Z または Ctrl+D)\n");

    while ((c = getchar()) != EOF) {
        if (isspace(c)) {
            continue;
        }

        if (isupper(c)) {
            upper_count++;
        } else if (islower(c)) {
            lower_count++;
        } else if (isdigit(c)) {
            digit_count++;
        } else {
            symbol_count++;
        }
    }

    puts("");
    puts("文字種別ごとの個数");
    printf("英大文字: %d\n", upper_count);
    printf("英小文字: %d\n", lower_count);
    printf("数字: %d\n", digit_count);
    printf("記号: %d\n", symbol_count);

    return 0;
}

解説

この問題では、toupper や tolower そのものではなく、同じ ctype.h の文字判定関数を組み合わせています。
文字変換の前に、どの種類の文字かを見分ける練習としてちょうどよい問題です。
isspace で空白類を除外している点もポイントです。

実践問題

入力された文字列に対して、次の変換を行うプログラムを作成してください。

  • 英大文字は英小文字に変換する
  • 英小文字は英大文字に変換する
  • 空白文字や英字以外はそのまま残す

解答例

ファイル名:12_9_3.c

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
    char str[100];

    printf("文字列を入力してください(最大99文字)> ");

    if (fgets(str, sizeof(str), stdin) == NULL) {
        puts("入力エラーが発生しました。");
        return 1;
    }

    size_t len = strlen(str);
    if (len > 0 && str[len - 1] == '\n') {
        str[len - 1] = '\0';
    }

    for (int i = 0; str[i] != '\0'; i++) {
        if (isupper((unsigned char)str[i])) {
            str[i] = (char)tolower((unsigned char)str[i]);
        } else if (islower((unsigned char)str[i])) {
            str[i] = (char)toupper((unsigned char)str[i]);
        }
    }

    puts("変換後の文字列:");
    printf("[%s]\n", str);

    return 0;
}

解説

この問題では、1文字ずつ順番に調べながら、大文字は小文字へ、小文字は大文字へ変換しています。
英字以外は何もしないので、そのまま残ります。
toupper と tolower を実際に文字列全体へ応用する練習としてとても良い問題です。

実践問題

空白とタブを含む文字列を入力し、次のように整形するプログラムを作成してください。

  • 連続した空白とタブは1つのスペースにまとめる
  • 文字列の先頭と末尾の空白は取り除く
  • 入力に失敗したらエラーメッセージを表示して return 1; で終了する

解答例

ファイル名:12_9_4.c

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main(void)
{
    char src[200];
    char dest[200];
    int i = 0;
    int j = 0;
    int in_space = 1;

    printf("文字列を入力してください> ");

    if (fgets(src, sizeof(src), stdin) == NULL) {
        puts("入力エラーが発生しました。");
        return 1;
    }

    size_t len = strlen(src);
    if (len > 0 && src[len - 1] == '\n') {
        src[len - 1] = '\0';
    }

    while (src[i] != '\0') {
        if (src[i] == ' ' || src[i] == '\t') {
            if (!in_space) {
                dest[j++] = ' ';
                in_space = 1;
            }
        } else {
            dest[j++] = src[i];
            in_space = 0;
        }
        i++;
    }

    if (j > 0 && dest[j - 1] == ' ') {
        j--;
    }

    dest[j] = '\0';

    puts("結果の文字列:");
    printf("\"%s\"\n", dest);

    return 0;
}

解説

この問題は toupper や tolower の直接利用ではありませんが、ctype.h を使う文字処理の考え方を広げる練習としてよい問題です。
空白の連続をまとめる処理では、直前が空白中かどうかを表すフラグ in_space を使っています。
文字列を1文字ずつ順番に見て処理する、という点では文字変換と同じ考え方が活きています。

文字変換関数を使うときの考え方

toupper と tolower を使うときは、次の流れで考えると整理しやすいです。

手順内容
11文字だけ変換したいのか、文字列全体を変換したいのか考える
2小文字を大文字にするなら toupper を選ぶ
3大文字を小文字にするなら tolower を選ぶ
4文字列なら \0 まで順に処理する
5英字以外はそのまま残ることを理解しておく

この流れを意識すると、文字変換の処理がとても書きやすくなります。

よくある使い方

やりたいこと使う関数
小文字を大文字にそろえるtoupperabc → ABC
大文字を小文字にそろえるtolowerABC → abc
入力文字を統一するtoupper / toloweryes, YES, Yes を同じ形に近づける
見やすく整形するtoupper / tolower表示用の文字列を整える
判定前に文字を統一するtolower など比較しやすい形にそろえる

toupper と tolower を学ぶ意味

この2つの関数はとてもシンプルですが、文字処理の基本としてとても重要です。

学べること内容
英字変換の基本大文字と小文字の変換方法
文字ごとの処理1文字ずつ順番に扱う考え方
英字以外の扱い数字や記号はそのまま残ること
入出力との連携getchar や fgets と組み合わせる方法
文字列処理への応用配列を順にたどって変換する方法

toupper と tolower を使えるようになると、入力文字を整えたり、表示形式をそろえたり、比較しやすい形に変換したりと、文字列処理の幅がぐっと広がります。
とても基本的な関数ですが、実際のプログラムでは何度も登場する大切な道具です。