Sign-up cleanup
The sign-up form for the next analogue mission, two weeks in a sealed habitat, has closed, and the list is a mess: names in capitals or with double spaces, emails with stray spaces, people who signed up twice, an entry with no name at all.
Clean it into a crew list the selection board can use, and say exactly what was dropped and why.
Finish stage 1 to unlock this stage.
Write clean_name(name), which trims the name, joins its words with single spaces and capitalises each word, and clean_email(email), which trims the email and makes it lower case. Print every sign-up, cleaned:
Anna Kowalska <anna.kowalska@example.org> Kenji Tanaka <k.tanaka@example.org> Chioma Okafor <chioma.okafor@example.org> Anna Kowalska <anna.kowalska@example.org> Olena Bondarenko-Shevchenko <olena.b@example.org> Priya Sharma <priya.sharma@example> <crew@example.org> Min-Jun Kim <minjun.kim@example.org> Kenji Tanaka <k.tanaka@example.org> Tomasz Nowak <tomasz nowak@example.org>
name.split() splits on any run of spaces and drops the ends, so " ".join(...) rebuilds it neatly; title() capitalises each word.
Finish stage 1 to unlock this stage.
Build the crew list. Reject a sign-up with no name, or with an email that fails valid_email(): exactly one @, something before it, a dot after it and no spaces. Drop a sign-up whose email is already on the list, naming who has it. Print each rejection as it happens, then the crew:
Rejected Anna Kowalska: duplicate of Anna Kowalska Rejected Priya Sharma: invalid email priya.sharma@example Rejected <crew@example.org>: missing name Rejected Kenji Tanaka: duplicate of Kenji Tanaka Rejected Tomasz Nowak: invalid email tomasz nowak@example.org Crew list: 5 people Anna Kowalska <anna.kowalska@example.org> Kenji Tanaka <k.tanaka@example.org> Chioma Okafor <chioma.okafor@example.org> Olena Bondarenko-Shevchenko <olena.b@example.org> Min-Jun Kim <minjun.kim@example.org>
Keep the emails seen so far in a dict, email -> name, so a duplicate can say whose it is.
Hints
String Methods - upper, lower, strip
# String methods - cleaning and checking text
# Imagine a noisy transmission coming in from a deep space probe
raw_signal = " voyager 1: still alive "
# .strip() removes whitespace from both ends
clean = raw_signal.strip()
print("Cleaned:", clean)
# .upper() and .lower() change case
print("Shouted:", clean.upper())
print("Whispered:", clean.lower())
# .title() capitalizes each word - useful for names and headers
print("Headline:", clean.title())
# Checking how a string starts or ends
mission_id = "ARTEMIS-II-2026"
print("Is Artemis?", mission_id.startswith("ARTEMIS"))
print("From 2026?", mission_id.endswith("2026"))
# Replacing parts of a string
log_entry = "Engine status: nominal"
print("Updated:", log_entry.replace("nominal", "OPTIMAL"))
Separate arguments with commas. They're passed on every Run as sys.argv[1:].