英字や数字の判定は、入力チェックやトークナイズ、フォーマット検証など多くの場面で必要になります。
本記事では<ctype.h>
に用意されているisalpha
とisdigit
の使い方を、初心者の方にもわかりやすいよう丁寧に解説します。
判定の基本、注意点、実用パターンまで順を追って説明します。
C言語での英字・数字判定
C言語では、文字が英字か数字かといった分類を行う関数群が<ctype.h>
に用意されています。
代表的なものがisalpha
(英字判定)とisdigit
(数字判定)です。
これらの関数は引数にint
を受け取り、真(非0)または偽(0)を返します。
使う前に#include <ctype.h>
を忘れないようにします。
もっとも重要な注意点は、これらの関数に渡す値はunsigned char
に変換可能なint
かEOF
でなければならないということです。
多くの環境でchar
は符号付きになり得るため、必ず(unsigned char)c
にキャストしてから渡すのが安全です。
これを怠ると未定義動作になる可能性があります。
また、isalpha
など一部の判定はロケールに依存します。
一方でisdigit
はロケール非依存で、常にASCIIの'0'
〜'9'
だけを数字とみなします。
UTF-8の全角数字(例: X
や1
)はisdigit
では数字と判定されません。
次の表に概要をまとめます。
関数名 | 判定対象 | 真(非0)になる例 | 偽(0)になる例 | 備考(注意) |
---|---|---|---|---|
isalpha | 英字 | 'A' , 'z' | '@' , '7' | ロケール依存。入力は(unsigned char) にキャスト |
isdigit | 数字 | '0' 〜'9' | 'A' , 全角数字'1' | ロケール非依存。ASCIIの数字のみ |
ポイントとして、これらの関数はbool
ではなくint
を返しますが、条件式では非0が真として扱われるため、if (isalpha(...))
のようにそのまま使います。
比較して== 1
のように書く必要はありません。
isalphaの使い方とコード例
英字かを判定する例
isalpha
は、引数の文字が英字(アルファベット)なら非0を返します。
大文字・小文字の区別なく判定されます。
#include <stdio.h>
#include <ctype.h>
// 文字が英字かを調べて表示するデモ
int main(void) {
const char s[] = "Az7#";
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
// 文字が英字かを調べて表示するデモ
int main(void) {
const char s[] = "Az7#";
for (size_t i = 0; s[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)s[i]; // 安全のためにunsigned charへ
if (isalpha(uc)) {
printf("%c は英字です\n", s[i]);
} else {
printf("%c は英字ではありません\n", s[i]);
}
}
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)s[i]; // 安全のためにunsigned charへ
if (isalpha(uc)) {
printf("%c は英字です\n", s[i]);
} else {
printf("%c は英字ではありません\n", s[i]);
}
}
return 0;
}
A は英字です
z は英字です
7 は英字ではありません
# は英字ではありません
常に(unsigned char)
にキャストしてから渡すのが安全です。
特に拡張ASCII(0x80以上)のバイト値を扱う可能性がある場合は必須です。
大文字と小文字の扱い
isalpha
は大文字と小文字を区別しないで英字と判定します。
#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "AaZz";
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "AaZz";
for (size_t i = 0; s[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)s[i];
printf("%c -> isalpha: %s\n", s[i], isalpha(uc) ? "true" : "false");
}
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)s[i];
printf("%c -> isalpha: %s\n", s[i], isalpha(uc) ? "true" : "false");
}
return 0;
}
A -> isalpha: true
a -> isalpha: true
Z -> isalpha: true
z -> isalpha: true
大文字・小文字の変換はtoupper
/tolower
で行えますが、本記事では判定に焦点を当てます。
英字でない場合の判定
英字以外を弾きたい場合は、否定演算子!
を使います。
数字や記号は「英字ではない」と判定されます。
#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "123!?_";
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "123!?_";
for (size_t i = 0; s[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (!isalpha(uc)) {
printf("%c は英字ではありません\n", s[i]);
}
}
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (!isalpha(uc)) {
printf("%c は英字ではありません\n", s[i]);
}
}
return 0;
}
1 は英字ではありません
2 は英字ではありません
3 は英字ではありません
! は英字ではありません
? は英字ではありません
_ は英字ではありません
UTF-8の日本語文字のような多バイト文字の各バイトに対してisalpha
を呼んでも、正しい“文字”判定にはなりません。
多言語の全文字を扱うなら<wctype.h>
のiswalpha
などワイド文字APIを検討します。
isdigitの使い方とコード例
数字かを判定する例
isdigit
はASCIIの'0'
〜'9'
のみを数字として扱います。
#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "5x09";
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "5x09";
for (size_t i = 0; s[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (isdigit(uc)) {
printf("%c は数字です\n", s[i]);
} else {
printf("%c は数字ではありません\n", s[i]);
}
}
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (isdigit(uc)) {
printf("%c は数字です\n", s[i]);
} else {
printf("%c は数字ではありません\n", s[i]);
}
}
return 0;
}
5 は数字です
x は数字ではありません
0 は数字です
9 は数字です
全角の1
やローマ数字Ⅳ
などはisdigit
では数字と判定されません。
‘0’〜’9’の範囲を確認
isdigit(c)
と'0' <= c && c <= '9'
は、ASCII環境では同じ結果になります。
以下で比較します。
#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "5A"; // '5' と 'A' を比較
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
int main(void) {
const char s[] = "5A"; // '5' と 'A' を比較
for (size_t i = 0; s[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)s[i];
int a = isdigit(uc); // ctype関数による判定
int b = ('0' <= s[i] && s[i] <= '9'); // 文字の範囲による判定
printf("%c -> isdigit:%d, 範囲チェック:%d\n", s[i], a, b);
}
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)s[i];
int a = isdigit(uc); // ctype関数による判定
int b = ('0' <= s[i] && s[i] <= '9'); // 文字の範囲による判定
printf("%c -> isdigit:%d, 範囲チェック:%d\n", s[i], a, b);
}
return 0;
}
5 -> isdigit:1, 範囲チェック:1
A -> isdigit:0, 範囲チェック:0
実務ではisdigit
を使うのが簡潔で読みやすいです。
範囲チェックは外部仕様で文字集合が明確なときに限って選択するとよいです。
文字列中の数字を数える
文字列に含まれる数字の個数を数える例です。
#include <stdio.h>
#include <ctype.h>
// 文字列中の数字の個数を数える
int main(void) {
const char *s = "Tel:+81-90-1234-5678";
int count = 0;
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
// 文字列中の数字の個数を数える
int main(void) {
const char *s = "Tel:+81-90-1234-5678";
int count = 0;
for (size_t i = 0; s[i] != '\0'; ++i) {
if (isdigit((unsigned char)s[i])) {
++count;
}
}
printf("数字の個数: %d\n", count);
return 0;
}
'; ++i) {
if (isdigit((unsigned char)s[i])) {
++count;
}
}
printf("数字の個数: %d\n", count);
return 0;
}
数字の個数: 12
電話番号やIDの抽出などでよく使うパターンです。
実用パターンと関連関数
文字列を走査して英字/数字を数える
英字と数字を同時に数えると、簡易的なバリデーションができます。
#include <stdio.h>
#include <ctype.h>
// 英字と数字の個数を同時に集計する
int main(void) {
const char *s = "Hello C99 world! 2025";
int alpha_count = 0;
int digit_count = 0;
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
// 英字と数字の個数を同時に集計する
int main(void) {
const char *s = "Hello C99 world! 2025";
int alpha_count = 0;
int digit_count = 0;
for (size_t i = 0; s[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (isalpha(uc)) {
++alpha_count;
} else if (isdigit(uc)) {
++digit_count;
}
// それ以外(空白・記号など)は今回は無視
}
printf("英字の個数: %d\n", alpha_count);
printf("数字の個数: %d\n", digit_count);
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (isalpha(uc)) {
++alpha_count;
} else if (isdigit(uc)) {
++digit_count;
}
// それ以外(空白・記号など)は今回は無視
}
printf("英字の個数: %d\n", alpha_count);
printf("数字の個数: %d\n", digit_count);
return 0;
}
英字の個数: 11
数字の個数: 6
クラス判定は「合致したら次へは行かない」ようにif
/else if
で順序付けすると読みやすくなります。
英数字の一括判定
英字または数字であるかを一度に判定したい場合は、isalnum
が便利です。
これはisalpha
とisdigit
の論理和に相当します。
#include <stdio.h>
#include <ctype.h>
// 英数字だけを抽出して新しい文字列を作る
int main(void) {
const char *src = "ID: X9-007_A";
char dst[64] = {0};
size_t j = 0;
for (size_t i = 0; src[i] != '#include <stdio.h>
#include <ctype.h>
// 英数字だけを抽出して新しい文字列を作る
int main(void) {
const char *src = "ID: X9-007_A";
char dst[64] = {0};
size_t j = 0;
for (size_t i = 0; src[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)src[i];
if (isalnum(uc)) { // 英数字ならコピー
dst[j++] = (char)uc;
}
// 記号や空白はスキップ
}
printf("元文字列: %s\n", src);
printf("英数字のみ: %s\n", dst);
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)src[i];
if (isalnum(uc)) { // 英数字ならコピー
dst[j++] = (char)uc;
}
// 記号や空白はスキップ
}
printf("元文字列: %s\n", src);
printf("英数字のみ: %s\n", dst);
return 0;
}
元文字列: ID: X9-007_A
英数字のみ: IDX9007A
ユーザーIDやファイル名の正規化などでよく使います。
アンダースコアはisalnum
では英数字に含まれない点に注意してください。
条件分岐の書き方
判定関数は非0/0を返すため、比較は不要です。
組み合わせる場合は論理演算子を使います。
#include <stdio.h>
#include <ctype.h>
// 文字を分類して表示する
int main(void) {
const char *s = "A1 _!";
for (size_t i = 0; s[i] != '#include <stdio.h>
#include <ctype.h>
// 文字を分類して表示する
int main(void) {
const char *s = "A1 _!";
for (size_t i = 0; s[i] != '\0'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (isalpha(uc)) {
printf("%c -> 英字\n", s[i]);
} else if (isdigit(uc)) {
printf("%c -> 数字\n", s[i]);
} else if (isspace(uc)) { // 関連関数: 空白類判定
printf("(space) -> 空白\n");
} else {
printf("%c -> その他\n", s[i]);
}
}
return 0;
}
'; ++i) {
unsigned char uc = (unsigned char)s[i];
if (isalpha(uc)) {
printf("%c -> 英字\n", s[i]);
} else if (isdigit(uc)) {
printf("%c -> 数字\n", s[i]);
} else if (isspace(uc)) { // 関連関数: 空白類判定
printf("(space) -> 空白\n");
} else {
printf("%c -> その他\n", s[i]);
}
}
return 0;
}
A -> 英字
1 -> 数字
(space) -> 空白
_ -> その他
! -> その他
書き方のコツとして、以下を押さえると安全で読みやすくなります。
(1) 引数は(unsigned char)
にキャストする、(2) 比較== 1
は不要、(3) 条件の優先順位を意図どおりに並べる。
まとめ
本記事では<ctype.h>
のisalpha
とisdigit
を中心に、英字・数字の判定方法と実用例を解説しました。
最重要ポイントは、引数を(unsigned char)
にキャストして未定義動作を避けること、そしてisdigit
はASCIIの'0'
〜'9'
のみを数字とするという仕様です。
英数字をまとめて判定するisalnum
や、空白判定isspace
など関連関数と組み合わせることで、入力検証やトークナイズ処理がシンプルに記述できます。
多言語の文字を扱う必要がある場合は<wctype.h>
のワイド文字版関数も検討すると良いでしょう。
用途に応じて適切な関数を選び、堅牢な文字処理を実現してください。