Check whether the given character is an alphabet or a numeric character or special character
Building on Question #14:
In the previous question, we detected uppercase vs lowercase. Now we expand to detect THREE categories!
Complete classification of all printable ASCII characters:
Category | ASCII Range | Examples | Count |
---|---|---|---|
Digits (0-9) | 48-57 | '0', '1', '2'... '9' | 10 characters |
Uppercase (A-Z) | 65-90 | 'A', 'B', 'C'... 'Z' | 26 characters |
Lowercase (a-z) | 97-122 | 'a', 'b', 'c'... 'z' | 26 characters |
Special Characters | Everything else! | @, #, $, %, space, etc. | 66+ characters |
Visual ASCII map (0-127):
0-31: Control characters (non-printable)
32: Space ' '
33-47: Special: ! " # $ % & ' ( ) * + , - . /
48-57: Digits: 0 1 2 3 4 5 6 7 8 9 ← NUMBER
58-64: Special: : ; < = > ? @
65-90: Uppercase: A B C ... X Y Z ← ALPHABET
91-96: Special: [ \ ] ^ _ `
97-122: Lowercase: a b c ... x y z ← ALPHABET
123-127: Special: { | } ~ DEL
Key observations:
Digit ASCII values in detail:
Character | ASCII | Character | ASCII |
---|---|---|---|
'0' | 48 | '5' | 53 |
'1' | 49 | '6' | 54 |
'2' | 50 | '7' | 55 |
'3' | 51 | '8' | 56 |
'4' | 52 | '9' | 57 |
⚠️ Critical distinction:
'7'
(character) = ASCII 557
(integer) = value 7Our solution structure:
if (ch >= '0' && ch <= '9')
cout << "NUMBER";
else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
cout << "ALPHABET";
else
cout << "SPECIAL CHARACTER";
Condition 1: Check for digits FIRST
ch >= '0' && ch <= '9'
ch >= 48 && ch <= 57
Condition 2: Check for alphabets (uppercase OR lowercase)
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
Breaking down the compound condition:
Part A: (ch >= 'a' && ch <= 'z')
ch >= 97 && ch <= 122
Part B: (ch >= 'A' && ch <= 'Z')
ch >= 65 && ch <= 90
Part C: ||
(OR operator)
Why use parentheses?
// ✅ CORRECT - Parentheses group each range check
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
// ❌ WRONG - Operator precedence issues!
ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'
Operator precedence (high to low):
>=
, <=
(comparison)&&
(AND)||
(OR)Parentheses override precedence and make intent clear!
Condition 3: Everything else = Special character
else
💡 Why this order works:
This is called the "specific to general" pattern!
Example 1: Digit (input = '7')
ch = '7'
(internally: ch = 55
)ch >= '0' && ch <= '9'
55 >= 48
→ TRUE ✅55 <= 57
→ TRUE ✅TRUE && TRUE
→ TRUE ✅cout << "NUMBER";
Example 2: Lowercase letter (input = 'a')
ch = 'a'
(internally: ch = 97
)97 >= 48 && 97 <= 57
97 >= 48
→ TRUE ✅97 <= 57
→ FALSE ❌TRUE && FALSE
→ FALSE ❌(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
97 >= 97 && 97 <= 122
→ TRUE ✅TRUE || anything
→ TRUE ✅ (short-circuit!)cout << "ALPHABET";
Example 3: Uppercase letter (input = 'Z')
ch = 'Z'
(internally: ch = 90
)90 >= 48 && 90 <= 57
→ FALSE ❌90 >= 97
→ FALSE ❌90 >= 65 && 90 <= 90
→ TRUE ✅FALSE || TRUE
→ TRUE ✅Example 4: Special character (input = '@')
ch = '@'
(internally: ch = 64
)64 >= 48 && 64 <= 57
64 >= 48
→ TRUE64 <= 57
→ FALSE ❌64 >= 97
→ FALSE ❌64 >= 65
→ FALSE ❌FALSE || FALSE
→ FALSE ❌else
Example 5: Edge case - '0' (first digit)
ch = '0'
(internally: ch = 48
)48 >= 48 && 48 <= 57
48 >= 48
→ TRUE ✅48 <= 57
→ TRUE ✅Example 6: Edge case - '9' (last digit)
ch = '9'
(internally: ch = 57
)57 >= 48 && 57 <= 57
→ TRUE ✅Example 7: Special - Space character (input = ' ')
ch = ' '
(internally: ch = 32
)32 >= 48
→ FALSE ❌Understanding our alphabet condition:
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
Truth table breakdown:
Input | Is Lowercase? | Is Uppercase? | Final (OR) | Result |
---|---|---|---|---|
'a' | TRUE | FALSE | TRUE | ALPHABET |
'Z' | FALSE | TRUE | TRUE | ALPHABET |
'5' | FALSE | FALSE | FALSE | Not alphabet |
'@' | FALSE | FALSE | FALSE | Not alphabet |
Why we need OR (||) here:
Alphabets exist in two separate ranges:
We need ||
to say: "It's an alphabet if it's in EITHER range!"
Short-circuit evaluation optimization:
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
Part A || Part B
For lowercase 'a':
TRUE || anything = TRUE
For uppercase 'Z':
FALSE || TRUE = TRUE
Common mistakes with compound conditions:
Mistake 1: Forgetting parentheses
// ❌ WRONG - Without parentheses
ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z'
// Due to precedence, this is interpreted as:
ch >= 'a' && (ch <= 'z' || ch >= 'A') && ch <= 'Z'
// WRONG LOGIC!
Mistake 2: Using AND instead of OR
// ❌ WRONG - Using && between ranges
(ch >= 'a' && ch <= 'z') && (ch >= 'A' && ch <= 'Z')
// Impossible! Can't be both lowercase AND uppercase!
Mistake 3: Incomplete range checks
// ❌ WRONG - Missing one comparison
ch >= 'a' && ch <= 'z' || ch >= 'A' // Missing upper bound!
// Would catch '{', '|', '}', '~' as uppercase!
💡 Rule for combining ranges:
&&
WITHIN each range check (both bounds must match)||
BETWEEN different ranges (either range works)Method 1: Our approach (explicit range checking)
if (ch >= '0' && ch <= '9')
cout << "NUMBER";
else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
cout << "ALPHABET";
else
cout << "SPECIAL CHARACTER";
✅ Clear logic
✅ No library needed
✅ Educational
Method 2: Using <cctype>
library
#include <cctype>
if (isdigit(ch))
cout << "NUMBER";
else if (isalpha(ch))
cout << "ALPHABET";
else
cout << "SPECIAL CHARACTER";
✅ Most professional
✅ Self-documenting
✅ Handles locale
✅ Shorter code
Method 3: Using ASCII values explicitly
if (ch >= 48 && ch <= 57)
cout << "NUMBER";
else if ((ch >= 97 && ch <= 122) || (ch >= 65 && ch <= 90))
cout << "ALPHABET";
else
cout << "SPECIAL CHARACTER";
✅ Functionally identical
❌ Less readable (magic numbers)
❌ Not recommended
Method 4: Reordering checks (alphabet first)
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
cout << "ALPHABET";
else if (ch >= '0' && ch <= '9')
cout << "NUMBER";
else
cout << "SPECIAL CHARACTER";
✅ Still correct
❌ Slightly less efficient (more complex check first)
Method 5: Using isalnum() for combined check
#include <cctype>
if (isalpha(ch))
cout << "ALPHABET";
else if (isdigit(ch))
cout << "NUMBER";
else if (!isalnum(ch))
cout << "SPECIAL CHARACTER";
isalnum()
= true if alphabet OR digit
Performance comparison:
Method | Speed | Readability | Best For |
---|---|---|---|
Manual checks | Fast | Good | Learning |
cctype library | Fast | Excellent | Production |
ASCII numbers | Fast | Poor | Never use |
💡 Industry practice:
<cctype>
functionsWhere character type classification is used:
1. Input Validation (Forms & User Input):
// Validate username: only letters, numbers, underscore
bool isValidUsername(string username) {
for (char c : username) {
if (!isalnum(c) && c != '_') {
return false; // Invalid character found
}
}
return true;
}
2. Password Strength Checker:
bool hasDigit = false, hasLetter = false, hasSpecial = false;
for (char c : password) {
if (isdigit(c)) hasDigit = true;
else if (isalpha(c)) hasLetter = true;
else hasSpecial = true;
}
if (hasDigit && hasLetter && hasSpecial)
cout << "Strong password!";
3. Lexer/Tokenizer (Compilers & Parsers):
4. Data Extraction & Parsing:
// Extract phone number from mixed text
string phone = "";
for (char c : text) {
if (isdigit(c)) {
phone += c;
}
}
// "Call me at 555-1234" → "5551234"
5. Text Sanitization:
// Remove special characters from text
string cleaned = "";
for (char c : text) {
if (isalnum(c) || c == ' ') {
cleaned += c;
}
}
// "Hello@World!" → "Hello World"
6. Email Validation:
7. Credit Card Validation:
// Check if string contains only digits
bool isValidCardNumber(string card) {
for (char c : card) {
if (!isdigit(c) && c != ' ' && c != '-') {
return false;
}
}
return true;
}
8. CSV/TSV Parsing:
9. Syntax Highlighting (Code Editors):
10. Natural Language Processing:
💡 Industry Insight: Character classification is the foundation of text processing, from simple validation to complex compiler design!
Progression through character problems:
Question #14: Two-way classification
&&
for range checksQuestion #15: Three-way classification (this!)
&&
and ||
New concepts introduced:
Comparison table:
Aspect | Question #14 | Question #15 |
---|---|---|
Categories | 2 (Upper/Lower) | 3 (Number/Alpha/Special) |
Ranges Checked | 2 (A-Z, a-z) | 3 (0-9, A-Z, a-z) |
Operators | && | && and || |
Complexity | Simple ranges | Compound conditions |
Default Case | NONE | SPECIAL CHARACTER |
Skills gained:
'0'
-'9'
)🎯 Next level preview:
Future problems might combine these concepts:
💡 Key Takeaway: Three-way classification uses if-else if-else pattern. Combine ranges with ||
, check within ranges with &&
. Always use parentheses to group conditions clearly. The else
case catches everything not matched above!
#include <iostream>
using namespace std;
int main() {
char ch;
cin >> ch;
if (ch >= '0' && ch <= '9')
cout << "NUMBER";
else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
cout << "ALPHABET";
else
cout << "SPECIAL CHARACTER";
return 0;
}