🌱 Phase 1 · Foundations 🟢 Beginner MODULE 03

Strings & Text

⏱️ 35 min read
📖 Theory + Code
🧩 5 Quiz Questions
🏗️ 1 Challenge
Your progress in Phase 150%
🎯 What you'll learn: How to create strings in Python, string indexing and slicing, 15+ essential string methods, powerful f-string formatting, escape characters, and common string operations like concatenation, repetition, and membership testing.

What is a String?

A string is a sequence of characters — letters, digits, spaces, symbols, or even emojis — wrapped in quotes. Strings are one of the most used data types in any programming language, because almost everything you show to a user is text.

In Python, strings are immutable — once created, you can't change individual characters. Instead, you create a new string from the original. This makes strings safe to pass around without fear of accidental changes.

💡
Strings are sequences
Because a string is a sequence of characters, Python lets you access individual characters by position (indexing), extract portions (slicing), loop through each character, and check whether a substring exists — all using the same syntax you'll later use on lists.
strings_intro.py
PYTHON
# Three ways to create strings
single  = 'Hello, Python!'       # single quotes
double  = "Hello, Python!"       # double quotes (same result)
triple  = """This string
spans multiple
lines."""                          # triple quotes = multi-line

print(single)
print(triple)

# Strings can hold any characters
mixed   = "Python 3.12 🐍"
digits  = "12345"          # this is TEXT, not a number
empty   = ""               # empty string — valid!
space   = " "              # one space — also a string

print(len(mixed))          # 13  (len counts characters)
print(len(empty))          # 0

Indexing & Slicing

Every character in a string has a position number called an index. Python indexes start at 0 (not 1!). You can also count from the end using negative indexes-1 is always the last character.

String:  "P y t h o n"
P
y
t
h
o
n
0
1
2
3
4
5
-6
-5
-4
-3
-2
-1
characters
positive indexes (left→right, start at 0)
negative indexes (right→left, start at -1)
indexing.py
PYTHON
lang = "Python"

# Positive indexing
print(lang[0])   # P  — first character
print(lang[1])   # y
print(lang[5])   # n  — last character

# Negative indexing
print(lang[-1])  # n  — last character
print(lang[-6])  # P  — first character

# IndexError — going out of bounds
# print(lang[10])  → IndexError: string index out of range

Slicing — Extract a Portion

Slicing lets you extract a substring using the syntax string[start:stop:step]. The start is inclusive, the stop is exclusive.

slicing.py
PYTHON
text = "BitWithBite"

# Basic slice: [start:stop]  (stop is excluded)
print(text[0:3])    # Bit  (chars at 0,1,2)
print(text[3:7])    # With
print(text[7:])     # Bite  (omit stop = go to end)
print(text[:3])     # Bit   (omit start = from beginning)
print(text[:])      # BitWithBite  (full copy)

# Step: [start:stop:step]
print(text[0:11:2]) # BtihBt  (every 2nd char)
print(text[::-1])   # etiByhtiwtiB  (reversed!)

# Negative slicing
print(text[-4:])    # Bite  (last 4 characters)
print(text[:-4])    # BitWith  (everything except last 4)
The reverse trick: [::-1]
The slice [::-1] is a classic Python one-liner for reversing any string (or list). It means: start at the end, go back to the beginning, step -1 (backwards). This is commonly asked in coding interviews!

Essential String Methods

Python strings come with 50+ built-in methods. You call them with dot notation: string.method(). Here are the most important ones you'll use daily.

.upper()
Convert all characters to uppercase
"hello".upper() → "HELLO"
.lower()
Convert all characters to lowercase
"HELLO".lower() → "hello"
.strip()
Remove whitespace from both ends
" hi ".strip() → "hi"
.replace(old, new)
Replace every occurrence of old with new
"cat".replace("c","b") → "bat"
.split(sep)
Split string into a list at separator
"a,b,c".split(",") → ["a","b","c"]
.join(iterable)
Join a list of strings into one string
",".join(["a","b","c"]) → "a,b,c"
.find(sub)
Return index of first match, -1 if not found
"python".find("th") → 2
.count(sub)
Count occurrences of substring
"banana".count("a") → 3
.startswith(pre)
Returns True if string starts with prefix
"hello".startswith("he") → True
.endswith(suf)
Returns True if string ends with suffix
"file.py".endswith(".py") → True
.title()
Capitalise first letter of every word
"hello world".title() → "Hello World"
.isdigit()
True if all characters are digits
"123".isdigit() → True
string_methods.py
PYTHON
name = "  fatima malik  "

# Clean up user input
clean = name.strip().title()
print(clean)                   # Fatima Malik

# Chaining methods
email = "  USER@Gmail.COM  "
print(email.strip().lower())   # user@gmail.com

# split + join
csv_row = "Ali,20,Karachi,Python"
fields = csv_row.split(",")
print(fields)                   # ['Ali', '20', 'Karachi', 'Python']
print(" | ".join(fields))        # Ali | 20 | Karachi | Python

# Validate input
code = "BWB2025"
print(code.startswith("BWB"))   # True
print(code.endswith("2025"))    # True

# replace
sentence = "I love Java. Java is great."
print(sentence.replace("Java", "Python"))
# I love Python. Python is great.
🎭
Methods return new strings — strings are immutable
Calling "hello".upper() doesn't change "hello" — it returns a brand-new string "HELLO". If you want to keep the result, you must assign it: name = name.upper(). This is the immutability of strings in action.

f-Strings — Modern String Formatting

An f-string (formatted string literal) is the modern, clean way to embed variables and expressions directly inside a string. Prefix the string with f and put variables inside {curly braces}.

f-strings were introduced in Python 3.6 and are now the recommended way to format strings — faster and more readable than older methods like % formatting or .format().

fstrings.py
PYTHON
name = "Sara"
age = 21
gpa = 3.85

# Basic f-string
print(f"Name: {name}")                     # Name: Sara
print(f"{name} is {age} years old.")        # Sara is 21 years old.

# Expressions inside braces
print(f"Birth year: {2025 - age}")          # Birth year: 2004
print(f"CGPA: {gpa * 100 / 4}%")            # CGPA: 96.25%

# Format numbers — decimal places
print(f"GPA: {gpa:.1f}")                    # GPA: 3.9  (1 decimal)
print(f"GPA: {gpa:.4f}")                    # GPA: 3.8500  (4 decimals)

# Call methods inside f-strings
print(f"Hello, {name.upper()}!")            # Hello, SARA!

# Multi-line f-strings
card = f"""
Student Card
────────────
Name: {name}
Age : {age}
GPA : {gpa:.2f}
────────────"""
print(card)
💡
Old vs New — always use f-strings
You may see older code using "Hello " + name (concatenation) or "Hello %s" % name (%-formatting) or "Hello {}".format(name). All work, but f-strings are cleaner, faster, and the modern standard. Use them exclusively.

Escape Characters

Some characters can't be typed directly inside a string — like a newline, a tab, or a backslash. You use an escape sequence: a backslash \ followed by a special character.

EscapeMeaningExampleOutput
\nNewline — move to next line"Hi\nWorld"Hi
World
\tTab — horizontal indent"Name:\tAli"Name:    Ali
\\Literal backslash"C:\\Users"C:\Users
\'Single quote inside single-quoted string'it\'s'it's
\"Double quote inside double-quoted string"say \"hi\""say "hi"
\rCarriage returnRare in modern use
escape_chars.py
PYTHON
# \n — newline
print("Line 1\nLine 2\nLine 3")
# Line 1
# Line 2
# Line 3

# \t — tab for alignment
print("Name:\tAli")
print("Score:\t99")

# Windows file paths — use \\ or r"raw string"
path1 = "C:\\Users\\Fatima\\Documents"
path2 = r"C:\Users\Fatima\Documents"  # raw string — same result
print(path1)
print(path2)

# Quotes inside strings
print('Python\'s syntax is clean')   # Python's syntax is clean
print("She said \"hello!\"")           # She said "hello!"
# Or just mix quote types (easier):
print("Python's syntax is clean")     # no escape needed

String Operations

Python supports several powerful operators that work directly on strings.

Concatenation: +
Joins two strings together. "Hello" + " " + "World""Hello World". Both sides must be strings.
✖️
Repetition: *
Repeats a string. "ha" * 3"hahaha". Great for separators like "-" * 40.
🔍
Membership: in
"py" in "python"True. Checks if substring exists. Case-sensitive!
📏
Length: len()
len("Python")6. Works on any sequence — strings, lists, tuples.
string_operations.py
PYTHON
# Concatenation
first = "Bit"
last  = "WithBite"
full  = first + last
print(full)                      # BitWithBite

# Repetition — great for dividers
print("=" * 30)                   # ==============================
print("ha" * 5)                   # hahahahaha

# Membership test
print("Bite" in full)             # True
print("java" in full)             # False
print("bite" in full)             # False  ← case-sensitive!
print("bite" in full.lower())    # True   ← convert to handle case

# Length
print(len(full))                   # 11
print(len(""))                     # 0  — empty string

# Practical: validate minimum password length
password = "mysecret"
if len(password) >= 8:
    print("Password is strong enough")
else:
    print("Password too short!")
⚠️
Can't concatenate str and int with +
"Score: " + 95 will throw a TypeError. You must convert: "Score: " + str(95). This is why f-strings are usually better — f"Score: {95}" handles the conversion for you automatically.
🧩 Knowledge Check
5 questions — test your mastery of Strings & Text
1. What does "Python"[1] return?
2. What does "hello world".upper() return?
3. What does "banana"[::-1] return?
4. What does "py" in "Python" return?
5. Which of the following correctly creates an f-string?
🏗️
Coding Challenge — Username & Bio Generator
Apply string methods, f-strings, slicing, and operations
Task: Write a program that:

1. Takes a full_name like " sara khan " and cleans it using .strip().title()
2. Generates a username by taking the first 4 characters of the cleaned first name, lowercased
3. Counts how many times the letter "a" appears in the full name (case-insensitive)
4. Checks if the name ends with "Khan" using a string method
5. Prints a formatted bio card using an f-string with the name, username, letter count, and the Khan check result
💡 Show hints
  • Use .strip().title() to clean the name
  • Use slicing first_name[:4].lower() for the username
  • Use .lower().count("a") for case-insensitive count
  • Use .endswith("Khan") to check surname
  • Use a triple-quote f-string for the multi-line card
username_generator.py — Sample Solution
PYTHON
# ── Username & Bio Generator ─────────────────
raw_name   = "  sara khan  "
full_name  = raw_name.strip().title()    # "Sara Khan"
first_name = full_name.split()[0]        # "Sara"
username   = first_name[:4].lower()     # "sara"

a_count  = full_name.lower().count("a") # 3
is_khan  = full_name.endswith("Khan")  # True

bio = f"""
╔══════════════════════╗
  User Profile
  Name     : {full_name}
  Username : @{username}
  Letter a : {a_count} times
  Is Khan  : {is_khan}
╚══════════════════════╝"""

print(bio)
🎉
Lesson 3 Complete!
Excellent! You've mastered Python strings. Next up — Operators.
← Course Home
Phase 1 · FoundationsLesson 3 of 6