A space club has badge names, coded signals, and messages to inspect. Your challenge is to reach the exact characters you need, clean messy text, and build tools that transform or search a message.
By the end, you will build a secret-message shifter, a position tool, and an alphabet scan report.
-
Find a character by its position and take part of a string with a slice.
-
Clean, test, split, and join text with string methods.
-
Check whether a character appears in text with
in. -
Build a new string one character at a time and search for a match.
-
Lesson 1: Reach into a String
Build badge initials
A string is a sequence of characters. Each character has a numbered position called an index. Python starts numbering at 0, so
[0]reaches the first character. Reach the first character of each name to build initials.first_name = "Maya" last_name = "Chen" initials = first_name[0] + last_name[0] print(initials)Scroll the code for more ↓
Output
MCThe initials are
MC. The brackets reach one character, sofirst_name[0]is itself a one-character string. Meaningful names such asfirst_nameandinitialshelp a reader understand the job.Now reach the last character with index
-1. Negative indexes count backward from the end.print(first_name[-1])Scroll the code for more ↓
Output
a-1selectsa, the last character ofMaya. Positive indexes still count from the front.Cut out a substring with a slice
A slice reaches a section of a string. In
text[a:b], positionais included and positionbis excluded. This is the same stop rule used byrange(a, b).signal = "ORBIT-739" word_part = signal[0:5] number_part = signal[6:9] print(word_part) print(number_part)Scroll the code for more ↓
Output
ORBIT 739Visible payoff: the two lines print
ORBITand then739. The first slice includes positions 0 through 4 but stops before 5. The second includes positions 6 through 8 but stops before 9. A slice is still a string, even when it contains only part of the original string.Leave one slice end open
An omitted start begins at the first character. Try
word[:3].word = "galaxy" print(word[:3])Scroll the code for more ↓
Output
galword[:3]printsgal; position 3 is excluded.An omitted stop continues to the end. Try
word[3:].print(word[3:])Scroll the code for more ↓
Output
axyword[3:]printsaxy. The two open-ended slices cover the whole word.Reverse with one special slice
The reversing slice
[::-1]reads a string from its last character back to its first.print(word[::-1])Scroll the code for more ↓
Output
yxalagThe result is
yxalag. This is the only step slice used in this unit.Recall
lenfrom Unit 07len(text)counts the characters in a string, as it did in Unit 07. Spaces and punctuation are characters too. Measure a badge label next.call_sign = "Blue Fox" size = len(call_sign) print(f"Badge text: {call_sign}") print("Characters: " + str(size))Scroll the code for more ↓
Output
Badge text: Blue Fox Characters: 8The f-string places the string value directly in a report. The next report uses
str(size)to convert the integer 8 into text before concatenating with+.Lesson 2: Clean and Test
Repair a messy signal
A control panel receives extra spaces and mixed capital letters. String methods are small tools attached to a string value. Start with
upper(), which makes uppercase text.signal = "Red Comet" print(signal.upper())Scroll the code for more ↓
Output
RED COMETupper()printsRED COMETand does not changesignal.Now use
lower()to make a separate lowercase version.print(signal.lower())Scroll the code for more ↓
Output
red cometThe result is
red comet; the savedsignalis stillRed Comet.Extra spaces at the beginning and end of a received line can be removed with
strip().raw_signal = " RED COMET " print(raw_signal.strip())Scroll the code for more ↓
Output
RED COMETThe printed text has no spaces at either end.
strip()leaves internal spaces in place.To change a matching piece of text, use
replace(old, new).print("red comet".replace("red", "blue"))Scroll the code for more ↓
Output
blue cometThe result is
blue comet; the old text was not edited in place.Now chain the four methods to clean, change, and announce one signal.
raw_signal = " RED COMET " clean_signal = raw_signal.strip().lower() changed_signal = clean_signal.replace("red", "blue") loud_signal = changed_signal.upper() print(clean_signal) print(changed_signal) print(loud_signal)Scroll the code for more ↓
Output
red comet blue comet BLUE COMETThe chain prints
red comet,blue comet, andBLUE COMET.strip()removes spaces only at the ends, and every method returns a new string. The originalraw_signalstays unchanged. Becausestrip()returns a string, you can call.lower()on that result right away.Find and recognize text
find(piece)reports the first matching position, or-1when no match exists.message = "moon rover" print(message.find("rover")) print(message.find("sun"))Scroll the code for more ↓
Output
5 -1The positions are
5and-1. A missing piece has no string index.startswithchecks the beginning;endswithchecks the end. Both return a boolean.filename = "mission.py" print(filename.startswith("mission")) print(filename.endswith(".py"))Scroll the code for more ↓
Output
True TrueBoth checks are
True; the methods test different ends of the same string.isdigit()checks that every character is a digit;isalpha()checks that every character is a letter.print("4071".isdigit()) print("orbit".isalpha()) print("-3".isdigit())Scroll the code for more ↓
Output
True True FalseThe first two checks are
True;"-3".isdigit()isFalse, so this simple digit check does not accept negative numbers.Join characters and walk words
A separator string can
jointhe characters of another string.print("-".join("abc"))Scroll the code for more ↓
Output
a-b-cThe result is
a-b-c. The separator goes between characters, with none at either end.split()lets a loop visit words separated by whitespace. Walk the words directly, without indexing the collection thatsplit()returns.line = "stars need fuel" for word in line.split(): print(word)Scroll the code for more ↓
Output
stars need fuelThe loop prints
stars,need, andfuelon separate lines. Eachwordis a string, soword[0]may reach its first character.Test membership
The
inoperator asks whether a character or substring appears in a string. It returns a boolean. Matching is case-sensitive, so cleaning case first can make a test dependable. The two tests below printTrueand thenFalse.message = "Launch at Dawn" quiet_message = message.lower() print("dawn" in quiet_message) print("moon" in quiet_message)Scroll the code for more ↓
Output
True FalseTry real input: read a PIN and check whether it has exactly four digits.
Try it pin = input("PIN: ") if len(pin) != 4: print(False) elif not pin.isdigit(): print(False) else: print(True)Scroll the code for more ↓
lenchecks the width andisdigit()rejects letters; this check also rejects a leading minus sign.Test a palindrome from both ends
A palindrome reads the same from left to right and right to left. Before checking both ends, walk through the positions of one short word.
w = "level" for i in range(len(w)): print(i, w[i])Scroll the code for more ↓
Output
0 l 1 e 2 v 3 e 4 lThe loop reports positions 0 through 4 and their characters. An index loop gives both a position and the character at that position.
Next compare just one mirror pair: the first and last characters.
w = "level" i = 0 print(w[i] == w[len(w) - 1 - i])Scroll the code for more ↓
Output
TrueThis one pair matches. A full palindrome check repeats the mirror comparison for half the word.
Now clean spaces and case, compare every mirror pair, and leave early at a mismatch.
def is_palindrome(text): cleaned = text.lower().replace(" ", "") for i in range(len(cleaned) // 2): if cleaned[i] != cleaned[len(cleaned) - 1 - i]: return False return True print(is_palindrome("Never odd or even")) print(is_palindrome("space camp"))Scroll the code for more ↓
Output
True FalseFor each loop counter
i, the left position isiand the matching right position islen(cleaned) - 1 - i. A mismatch returnsFalseimmediately.return Truebelongs after the loop because every tested pair must match first.Try real input: read a word or phrase and ask the palindrome function about it.
Try it word = input("Word: ") print(is_palindrome(word))Scroll the code for more ↓
The typed text replaces the fixed sample; the function returns one boolean.
Count vowels by condition
A counter can grow only when the current character passes a membership test. The report below prints
Vowels: 5.A
forloop can walk directly through a string:for ch in text:gives each character in order. This is a value loop: use it when the character itself matters. An index loop such asfor i in range(len(text)):is different: it gives positions, as in the palindrome example above and the position example later.word = "sun" for ch in word: print(ch)Scroll the code for more ↓
Output
s u nThe loop prints
s,u, andnin order. It visits characters directly, without using their indexes.Now count only characters that are vowels, using a condition inside the character loop.
def vowel_count(text): total = 0 cleaned = text.lower() for ch in cleaned: if ch in "aeiou": total = total + 1 return total amount = vowel_count("Solar eclipse") print(f"Vowels: {amount}")Scroll the code for more ↓
Output
Vowels: 5Choose among three character kinds
Membership tests also fit an
if/elif/elsebranch. Test the narrow vowel case first, the wider alphabet case second, and everything else last. The three calls below printvowel,consonant, andother.def character_kind(ch): letter = ch.lower() if letter in "aeiou": return "vowel" elif letter in "abcdefghijklmnopqrstuvwxyz": return "consonant" else: return "other" print(character_kind("E")) print(character_kind("z")) print(character_kind("?"))Scroll the code for more ↓
Output
vowel consonant otherLesson 3: Transform and Search
Build a new string one character at a time
A transmission effect needs every character doubled. Strings can be accumulated with
+: begin with an empty string, transform each character, and save the growing result.def double_letters(text): transformed = "" for ch in text: transformed = transformed + ch + ch return transformed print(double_letters("Go!")) print(double_letters("42"))Scroll the code for more ↓
Output
GGoo!! 4422Visible payoff: the calls print
GGoo!!and then4422. The accumulatortransformedstarts empty. Each loop trip adds the current character twice. The function returns a new string; it does not changetext. This is the transform-each pattern.Try real input: read one line, count its words, and print the count.
Try it line = input("Line: ") count = 0 for word in line.split(): count = count + 1 print(f"Words: {count}")Scroll the code for more ↓
Each word contributes one to the count, including words after extra spaces.
Search from left to right
A navigation display needs the first position of one character. Visit positions in order. Return the loop counter as soon as the character matches, or return
-1only after the whole loop ends.def position(text, ch): for i in range(len(text)): if text[i] == ch: return i return -1 print(position("meteor", "e")) print(position("meteor", "x"))Scroll the code for more ↓
Output
1 -1The first call returns the integer 1. The second returns
-1, the signal that no position matched. Returning inside the loop preserves the first match. Returning-1inside the loop would stop too early. The short report below printsSaved position: 4.saved_position = position("satellite", "l") report = "Saved position: " + str(saved_position) print(report)Scroll the code for more ↓
Output
Saved position: 4Count one chosen character
Searching for the first match and counting every match are related but different jobs. For a character count, keep walking after a match and update an integer counter. The two calls below print
2and then0.def count_char(text, ch): matches = 0 for current in text: if current == ch: matches = matches + 1 return matches print(count_char("balloon", "l")) print(count_char("balloon", "z"))Scroll the code for more ↓
Output
2 0Print an alphabet scan table
A report can scan the alphabet one letter at a time. The outer loop chooses a letter, and
count_charscans the message for that letter.printwrites one table row per alphabet letter.def print_letter_table(text): alphabet = "abcdefghijklmnopqrstuvwxyz" cleaned = text.lower() print("letter | total") for letter in alphabet: total = count_char(cleaned, letter) print(f"{letter} | {total}") print_letter_table("Cabana!")Scroll the code for more ↓
Output
letter | total a | 3 b | 1 c | 1 d | 0 e | 0 f | 0 g | 0 h | 0 i | 0 j | 0 k | 0 l | 0 m | 0 n | 1 o | 0 p | 0 q | 0 r | 0 s | 0 t | 0 u | 0 v | 0 w | 0 x | 0 y | 0 z | 0The table always has one row for each of the 26 lowercase letters. For
Cabana!, the nonzero rows area | 3,b | 1,c | 1, andn | 1; all other rows show0. It reports every total without choosing a winning letter. The loops make each scan step visible.Challenge: Shift a message
A Caesar shift moves each letter forward through the alphabet. Build the search helper first. Then lowercase the message, search the alphabet for each character, and use remainder arithmetic to wrap from
ztoa. Nonletters pass through unchanged. Herek >= 0.def position(alphabet, ch): for i in range(len(alphabet)): if alphabet[i] == ch: return i return -1 def shift(message, k): alphabet = "abcdefghijklmnopqrstuvwxyz" shifted = "" cleaned = message.lower() for ch in cleaned: pos = position(alphabet, ch) if pos == -1: shifted = shifted + ch else: new_pos = (pos + k) % 26 shifted = shifted + alphabet[new_pos] return shifted print(shift("Meet at 8!", 3)) print(shift("Zebra", 2))Scroll the code for more ↓
Output
phhw dw 8! bgdtcChallenge payoff: the calls print
phhw dw 8!and thenbgdtc.Put it together: indexing reaches one character, and slices reach a section or reverse a string. The string methods taught here clean, inspect, and join text;
intests membership. Counter loops measure matches, transform-each loops build new strings, and a left-to-right search returns a position or-1.-
text[0]reaches the first character;text[1:4]takes positions 1 through 3. -
String methods can change case, trim spaces, replace text, or split a line into words.
-
intests whether a character or smaller string appears in a string. -
A loop can add transformed characters to a new string without changing the original.
-
A search checks positions in order and can return the match's position or
-1.
You can now inspect, clean, transform, and search the space club's messages.
-