Edge Cases & Parsing
Learn to handle input validation, boundary conditions, null/empty checks, string parsing, type coercion pitfalls, and overflow — the defensive coding skills that separate robust solutions from fragile ones.
Learn & Reference
Understanding the Pattern
Edge Cases & Parsing
Writing code that works for the happy path is easy. Writing code that handles every weird, broken, or unexpected input is what separates solid engineers from the rest. Edge case handling and input parsing are skills you will use in every single interview problem, even if the problem itself is not "about" parsing.
Input Validation Patterns
Before processing any input, ask yourself: what could go wrong?
- Empty or null input — what does your function return for
"",null,undefined, ornil? - Single element — does your algorithm work when the input has exactly one character, one element, or one digit?
- Whitespace — does leading, trailing, or excessive internal whitespace break your parser?
- Unexpected characters — what happens when letters appear where digits are expected, or vice versa?
Boundary Conditions
Off-by-one errors and boundary conditions are the most common source of bugs in interviews:
- Off-by-one — is your loop bound
<or<=? Does your index start at 0 or 1? - Empty input — the string is
"", the array is[], the number is0 - Single element — only one character, one item, one digit
- Maximum/minimum values — 32-bit integer overflow (
2^31 - 1 = 2147483647,-2^31 = -2147483648) - Negative numbers — does your code handle the sign correctly?
String-to-Number Parsing
Converting strings to numbers is deceptively tricky:
- Skip leading whitespace —
" 42"should parse as42 - Handle optional sign —
"+42"and"-42"are both valid - Stop at first non-digit —
"42abc"should parse as42 - Overflow clamping — results outside the 32-bit range must be clamped
Type Coercion Pitfalls
Different languages handle type coercion differently:
- JavaScript:
"" == falseistrue,"0" == falseistrue,null == undefinedistrue - Python: empty string is falsy,
0is falsy, empty list is falsy - Java:
Integer.parseInt()throwsNumberFormatExceptionon invalid input - Go:
strconv.Atoi()returns an error (no exceptions)
Integer Overflow Handling
In languages with fixed-width integers (Java, Go, C++), arithmetic can silently overflow:
- 32-bit signed range:
-2,147,483,648to2,147,483,647 - Check before multiplying: if
result > MAX / 10, the nextresult * 10 + digitwill overflow - Python exception: Python integers have arbitrary precision — no overflow, but interview problems often ask you to enforce 32-bit limits
Whitespace & Formatting Edge Cases
- Leading/trailing whitespace — always trim unless the problem says otherwise
- Multiple consecutive spaces — should they collapse to one? Or be preserved?
- Tabs, newlines, carriage returns — are these "whitespace" in your context?
- Empty string after trimming — trimming
" "gives""
Common Mistakes
- Not handling empty input: forgetting to check for empty strings or null values before processing, leading to index-out-of-bounds or null pointer errors
- Ignoring leading/trailing whitespace: many inputs have hidden whitespace that breaks comparisons and parsing
- Off-by-one in boundary checks: using
>=instead of>when checking overflow, or starting a loop at the wrong index - Silent overflow in Java/Go/C++: multiplying or adding without checking if the result exceeds the 32-bit range first
- Forgetting the negative sign: parsing
"-42"but only handling digits, losing the sign - Case sensitivity in string comparisons:
"True"vs"true"vs"TRUE"— normalize before comparing - Not stopping at invalid characters: continuing to parse after encountering a non-digit character when building a number
- Assuming well-formed input: real interview inputs include empty strings, single characters, all-whitespace strings, and garbage data
When to Use
Template
1# --- Safe Parse with Default ---2def safe_parse_int(s, default=0):3try:4return int(s.strip())5except (ValueError, AttributeError):6return default78# --- Character-by-Character Parsing ---9def parse_digits(s):10i = 011# Skip whitespace12while i < len(s) and s[i] == ' ':13i += 114# Handle sign15sign = 116if i < len(s) and s[i] in '+-':17sign = -1 if s[i] == '-' else 118i += 119# Parse digits20result = 021while i < len(s) and s[i].isdigit():22result = result * 10 + int(s[i])23i += 124return result * sign2526# --- Validate Input Before Processing ---27def process(s):28if not s or not s.strip():29return None # handle empty/whitespace30s = s.strip()31# ... process cleaned input
Syntax Reference
1# === String Parsing ===2int("42") # string to int: 42 (raises ValueError on invalid)3float("3.14") # string to float: 3.144str(42) # int to string: "42"5s.strip() # trim whitespace6s.lstrip() # trim left only7s.rstrip() # trim right only8s.isdigit() # all digits? (no sign, no decimal)9s.isnumeric() # numeric chars? (broader than isdigit)10s.isalpha() # all letters?11s.isalnum() # letters or digits?1213# === Safe Parsing ===14try:15val = int(s)16except ValueError:17val = 0 # default on failure1819# === Regex ===20import re21re.findall(r'-?\d+', s) # find all integers (with optional negative)22re.match(r'^[+-]?\d+$', s) # match entire string as integer23re.sub(r'\s+', ' ', s) # collapse whitespace2425# === Overflow Constants ===26INT_MAX = 2**31 - 1 # 214748364727INT_MIN = -(2**31) # -2147483648
Common Recipes
1# --- Safe String to Integer (atoi) ---2def safe_atoi(s):3s = s.strip()4if not s:5return 06sign = 17i = 08if s[i] in '+-':9sign = -1 if s[i] == '-' else 110i += 111result = 012while i < len(s) and s[i].isdigit():13result = result * 10 + int(s[i])14i += 115result *= sign16return max(-(2**31), min(2**31 - 1, result))1718# --- Validate Number Format ---19def is_number(s):20s = s.strip()21if not s:22return False23i = 024if s[i] in '+-':25i += 126has_digit = False27has_dot = False28while i < len(s):29if s[i].isdigit():30has_digit = True31elif s[i] == '.' and not has_dot:32has_dot = True33else:34return False35i += 136return has_digit3738# --- Compare Version Strings ---39def compare_versions(v1, v2):40parts1 = list(map(int, v1.split('.')))41parts2 = list(map(int, v2.split('.')))42n = max(len(parts1), len(parts2))43for i in range(n):44a = parts1[i] if i < len(parts1) else 045b = parts2[i] if i < len(parts2) else 046if a < b: return -147if a > b: return 148return 0
Complexity
| Operation | Time | Notes |
|---|---|---|
| String to integer (atoi) | O(n) | Single pass through digits |
| Number validation | O(n) | Single pass through characters |
| Whitespace normalization | O(n) | Scan and rebuild string |
| Overflow detection | O(n) | Check during digit parsing |
| Regex matching | O(n) | Linear for simple patterns |
| Version comparison | O(n) | n = total length of both strings |
| Email validation | O(n) | Single pass with state tracking |
Watch Out
- ✗Not handling empty input: forgetting to check for empty strings or null values before processing, leading to index-out-of-bounds or null pointer errors
- ✗Ignoring leading/trailing whitespace: many inputs have hidden whitespace that breaks comparisons and parsing
- ✗Off-by-one in boundary checks: using `>=` instead of `>` when checking overflow, or starting a loop at the wrong index
- ✗Silent overflow in Java/Go/C++: multiplying or adding without checking if the result exceeds the 32-bit range first
- ✗Forgetting the negative sign: parsing `"-42"` but only handling digits, losing the sign
- ✗Case sensitivity in string comparisons: `"True"` vs `"true"` vs `"TRUE"` — normalize before comparing
- ✗Not stopping at invalid characters: continuing to parse after encountering a non-digit character when building a number
- ✗Assuming well-formed input: real interview inputs include empty strings, single characters, all-whitespace strings, and garbage data