Write a function that masks all but the last four digits of a digit string, replacing the rest with *.
mask_phone_number(s)
s is a string of digits. Replace every digit except the last four with "*". If s has 4 or fewer digits, return it unchanged (nothing to mask).
mask_phone_number("5551234567") // → "******4567" (10 digits, last 4 kept)
mask_phone_number("123456") // → "**3456" (6 digits, last 4 kept)
mask_phone_number("1234") // → "1234" (exactly 4, nothing masked)
import re
def mask_phone_number(s):
return re.sub(r"\d(?=\d{4})", "*", s)
This is the exact lookahead example from the patterns-and-groups lesson, put to use. The pattern \d(?=\d{4}) reads as: match a digit, but only if it's immediately followed by exactly 4 more digits — and importantly, the lookahead (?=\d{4}) doesn't consume those 4 digits, so they remain available to be checked (and not matched/replaced) as the scan continues.
Walk through "5551234567" (10 digits): the scan checks each position — is there a digit here, followed by at least 4 more digits? For the first 6 digits (555123), yes — each has at least 4 digits after it, so re.sub replaces all 6 with *. The last 4 digits (4567) each fail the lookahead (there aren't 4 more digits after them), so they're left untouched. Result: "******4567".
For "1234" (exactly 4 digits), no digit has 4 more digits following it — even the very first 1 only has 3 digits after it (234). So nothing matches the pattern, and re.sub returns the string unchanged, which is exactly the required "4 or fewer digits" behavior — no special-case code needed at all, since the lookahead naturally handles it.
import re
def mask_phone_number(s):
return re.sub(r"\d(?=\d{4})", "*", s)
Sign in to join the discussion.
No comments yet. Be the first to ask a question.
Press Run to execute your code, or Submit to test and complete this problem.