Validate Email
A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- medium
- Seniority
- L3
Problem
Does a string arriving at our signup form look like an email: exactly one '@' with something before it, and a domain after it whose first '.' has at least one character on each side? Return True if so and False otherwise; no other character matters.
Looks like an email. But is it?
Example 1
Input:
email = "analyst@company.com"
Output:
true
Example 2
Input:
email = "bad-email"
Output:
false
Worked solution and explanation
Why this problem exists in real interviews
This is positional parsing dressed up as a membership check. Everyone writes '@' in email and '.' in email; that line accepts 'an.alyst@company', 'chen@@data.com' and 'analyst@.com', because the question was never WHETHER the characters appear but WHERE they sit. The candidates who pass split once, on exactly one '@', and then interrogate only the piece after it.
Break down the requirements
Step 1: Guard on exactly one '@'
Check email.count('@') != 1 first and bail out. Only then is local, domain = email.split('@') guaranteed to unpack into two pieces; skip the count and 'chen@@data.com' raises a ValueError instead of returning False.
Step 2: Reject an empty part before the '@'
Return early when local is empty. This is the one rule the domain check cannot cover for you: '@company.com' has a perfectly valid domain, so without this guard it sails through.
Step 3: Let the first dot decide the domain
domain.partition('.') splits on the first dot and hands back an empty tail when there is no dot at all. So 'analyst@company', 'analyst@.com', 'analyst@company.' and an empty domain all fail one check: bool(head) and bool(tail).
The solution
def is_valid_email(email: str) -> bool:
if email.count('@') != 1:
return False
local, domain = email.split('@')
if not local:
return False
head, _, tail = domain.partition('.')
return bool(head) and bool(tail)Common follow-up questions
- How would you also reject local parts that start or end with a dot? (Most real validators forbid '.foo@bar.com' and 'foo.@bar.com'. Add a check on the first and last character of `local` and discuss why the spec did not require it here.)
- What changes if every label between dots in the domain must be non-empty? (Switch from `partition` to `domain.split('.')` and require every label to be non-empty, so 'a@b..c' fails.)
- Would you implement this with `re.fullmatch` in production? (Compare a single `re.fullmatch` against the readable rule list: a regex is fine when the spec is stable, rule lists are easier to extend and debug.)