15. Alphabet or Number or Special Character

Easy ⏱️ 12 min

Problem Statement

Check whether the given character is an alphabet or a numeric character or special character

Input Format:
Enter a Character as input
Output Format:
Print the output as "NUMBER" or "ALPHABET" or "SPECIAL CHARACTER"
Constraints:
0 <= CHARACTER <= 2^7
Sample Input 1:
a
Sample Output 1:
ALPHABET
Sample Input 2:
7
Sample Output 2:
NUMBER
🎯 Three-Way Classification - Expanding Character Detection
📊 The Complete ASCII Character Map

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:

  • 📌 Digits: Continuous range 48-57
  • 📌 Alphabets: Two ranges (65-90 and 97-122)
  • 📌 Special chars: Everything else (gaps + ends)

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 55
  • 7 (integer) = value 7
  • They are NOT the same!
🔍 Breaking Down the Logic - Order Matters!

Our 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'

  • Converts to: ch >= 48 && ch <= 57
  • Range check: 48 ≤ ch ≤ 57
  • Catches: '0', '1', '2', ... '9'
  • Why first? Simplest check, most efficient

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')

  • Checks lowercase range
  • Converts to: ch >= 97 && ch <= 122
  • Catches: 'a', 'b', 'c', ... 'z'

Part B: (ch >= 'A' && ch <= 'Z')

  • Checks uppercase range
  • Converts to: ch >= 65 && ch <= 90
  • Catches: 'A', 'B', 'C', ... 'Z'

Part C: || (OR operator)

  • TRUE if EITHER condition is true
  • Combines both uppercase and lowercase
  • Total: 52 letters (26 + 26)

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):

  1. >=, <= (comparison)
  2. && (AND)
  3. || (OR)

Parentheses override precedence and make intent clear!

Condition 3: Everything else = Special character

else

  • No condition needed!
  • Catches ALL remaining characters
  • Includes: @, #, $, %, space, punctuation, etc.

💡 Why this order works:

  1. Check digits (smallest specific range)
  2. Check alphabets (two ranges combined)
  3. Default to special (everything else)

This is called the "specific to general" pattern!

🔍 Step-by-Step Execution Examples

Example 1: Digit (input = '7')

  1. Read: ch = '7' (internally: ch = 55)
  2. Check condition 1: ch >= '0' && ch <= '9'
    • 55 >= 48 → TRUE ✅
    • 55 <= 57 → TRUE ✅
    • TRUE && TRUE → TRUE ✅
  3. Execute: cout << "NUMBER";
  4. Output: "NUMBER"

Example 2: Lowercase letter (input = 'a')

  1. Read: ch = 'a' (internally: ch = 97)
  2. Check condition 1: 97 >= 48 && 97 <= 57
    • 97 >= 48 → TRUE ✅
    • 97 <= 57 → FALSE ❌
    • TRUE && FALSE → FALSE ❌
  3. Check condition 2: (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
    • Part A: 97 >= 97 && 97 <= 122 → TRUE ✅
    • TRUE || anything → TRUE ✅ (short-circuit!)
  4. Execute: cout << "ALPHABET";
  5. Output: "ALPHABET"

Example 3: Uppercase letter (input = 'Z')

  1. Read: ch = 'Z' (internally: ch = 90)
  2. Check digits: 90 >= 48 && 90 <= 57 → FALSE ❌
  3. Check alphabets:
    • Part A (lowercase): 90 >= 97 → FALSE ❌
    • Part B (uppercase): 90 >= 65 && 90 <= 90 → TRUE ✅
    • FALSE || TRUE → TRUE ✅
  4. Output: "ALPHABET"

Example 4: Special character (input = '@')

  1. Read: ch = '@' (internally: ch = 64)
  2. Check digits: 64 >= 48 && 64 <= 57
    • 64 >= 48 → TRUE
    • 64 <= 57 → FALSE ❌
    • Result: FALSE
  3. Check alphabets:
    • Lowercase: 64 >= 97 → FALSE ❌
    • Uppercase: 64 >= 65 → FALSE ❌
    • FALSE || FALSE → FALSE ❌
  4. Go to else
  5. Output: "SPECIAL CHARACTER"

Example 5: Edge case - '0' (first digit)

  1. Read: ch = '0' (internally: ch = 48)
  2. Check digits: 48 >= 48 && 48 <= 57
    • 48 >= 48 → TRUE ✅
    • 48 <= 57 → TRUE ✅
  3. Output: "NUMBER"

Example 6: Edge case - '9' (last digit)

  1. Read: ch = '9' (internally: ch = 57)
  2. Check: 57 >= 48 && 57 <= 57 → TRUE ✅
  3. Output: "NUMBER"

Example 7: Special - Space character (input = ' ')

  1. Read: ch = ' ' (internally: ch = 32)
  2. Check digits: 32 >= 48 → FALSE ❌
  3. Check alphabets: Both ranges fail
  4. Output: "SPECIAL CHARACTER"
⚡ Compound Conditions - Mastering && and ||

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:

  • Range 1: 65-90 (A-Z)
  • Gap: 91-96 (special chars: [ \ ] ^ _ `)
  • Range 2: 97-122 (a-z)

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':

  • Part A evaluates: TRUE ✅
  • TRUE || anything = TRUE
  • Part B is never evaluated (short-circuit!)
  • Performance boost!

For uppercase 'Z':

  • Part A evaluates: FALSE ❌
  • Must check Part B...
  • Part B evaluates: TRUE ✅
  • 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:

  • Use && WITHIN each range check (both bounds must match)
  • Use || BETWEEN different ranges (either range works)
  • Always use parentheses for clarity!
🎯 Alternative Approaches & Optimizations

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:

  • Production code: Use <cctype> functions
  • Competitive programming: Manual checks (faster to type)
  • Learning: Manual checks (understand logic)
🌍 Real-World Applications

Where 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):

  • Identify variable names (start with letter)
  • Detect numeric literals (strings of digits)
  • Recognize operators (special characters)

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:

  • Local part: letters, digits, some special chars
  • Domain: letters, digits, hyphens, dots
  • Must validate each character type

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:

  • Detect field separators (special chars)
  • Handle quoted strings vs numbers
  • Escape special characters

9. Syntax Highlighting (Code Editors):

  • Color keywords (letters)
  • Highlight numbers (digits)
  • Show operators (special chars)

10. Natural Language Processing:

  • Separate words from punctuation
  • Extract hashtags/mentions (@, #)
  • Count alphanumeric vs symbols

💡 Industry Insight: Character classification is the foundation of text processing, from simple validation to complex compiler design!

📚 Building on Previous Knowledge

Progression through character problems:

Question #14: Two-way classification

  • Uppercase vs Lowercase vs None
  • Two ranges to check (A-Z, a-z)
  • Used && for range checks

Question #15: Three-way classification (this!)

  • Number vs Alphabet vs Special Character
  • Three ranges to check (0-9, A-Z, a-z)
  • Used both && and ||
  • More complex compound conditions

New concepts introduced:

  1. OR operator (||): Combining multiple ranges
  2. Digit detection: New ASCII range (48-57)
  3. Three-way branching: if-else if-else pattern
  4. Compound conditions: Nested logic with parentheses
  5. Default category: "Everything else" approach

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:

  • ✅ Character digit detection ('0'-'9')
  • ✅ Combining multiple conditions with OR
  • ✅ Proper parentheses usage in logic
  • ✅ Short-circuit evaluation optimization
  • ✅ Three-way classification pattern

🎯 Next level preview:

Future problems might combine these concepts:

  • Count digits vs letters in a string
  • Validate complex patterns (emails, URLs)
  • Character-based encryption/decryption
  • Text processing and transformation

💡 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!

Solution

#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;
}