Strings: Intermediate
SendGrid delivers over 100 billion emails per year for companies like Uber, Spotify, and Airbnb, and the engine behind every one of those personalized messages is Python string formatting. A single email template becomes millions of individually addressed messages by merging customer names, order IDs, and dynamic content using f-strings and format operations. The string formatting, join, replace, find, and regex basics you learn in this lesson are exactly how SendGrid transforms a generic design into a message that feels written for you specifically.
String Indexing
Zero-Based Indexing
- P = index 0 (first character)
- y = index 1
- t = index 2
- h = index 3
- o = index 4
- n = index 5 (last character)
Negative Indexing
- Counts from start
- text[0] = first char
- text[5] = 6th char
- Counts from end
- text[-1] = last char
- text[-6] = 6th from end
> A string "Python" is accessed using both positive and negative indexing. Pick the correct negative index to get the last character, and the correct positive index to get the first character.
text = "Python" first = text[] last = text[] print(first) print(last)
Index Out of Range
This raises IndexError: string index out of range. Always check the string length before accessing by index if the position might be invalid.
String Slicing
The first slice [0:6] returns "Python" (characters 0 through 5). The second [7:18] returns "Programming" (characters 7 through 17).
Slice Defaults
You can omit the start or end index. Omitting start defaults to 0. Omitting end defaults to the string length.
text[:6] gives "Python" (from start to index 6). text[7:] gives "Programming" (from index 7 to end). text[:] creates a copy of the entire string.
Negative Slice Indices
This extracts "pdf" using filename[-3:] (last 3 characters) and "document" using filename[:-4] (everything except last 4 characters including the dot).
Slice Step
text[::2] gives "Pto" (every other character). text[1::2] gives "yhn" (every other starting from index 1). text[::-1] gives "nohtyP" (reversed string).
Searching in Strings
The in Operator
The in operator checks if a substring exists within a string. It returns True or False.
find() and index()
.find() returns the position of the first occurrence of a substring, or -1 if not found. .index() does the same but raises an error if not found.
- Returns -1 if not found
- Safe for conditional checks
- Use when substring might not exist
- Raises ValueError if not found
- Use when substring must exist
- Crashes if assumption wrong
The count() Method
.count() returns the number of non-overlapping occurrences of a substring:
startswith() and endswith()
True if the filename ends with any of those extensions.> You need to validate a filename by checking its extension and counting how many dots it contains. Pick the correct method to test if the string ends with ".csv", and the correct method to count occurrences of a character.
name = "data.backup.csv" print(name.(".csv")) print(name.("."))
startswith() and endswith() are cleaner than slicing for prefix and suffix checks. They also accept a tuple of options, so filename.endswith((".pdf", ".docx", ".txt")) checks all three extensions in a single readable call.
count() returns how many non-overlapping times a substring appears in a string. It is useful for quick frequency checks, such as counting how many dots are in a filename to determine if it has multiple extensions.
in operator is the most readable choice: if ".csv" in filename:.String Transformation
strip(), lstrip(), rstrip()
.strip() removes whitespace from both ends of a string. .lstrip() removes from the left only, .rstrip() from the right only.
The replace() Method
.replace() substitutes all occurrences of a substring with another:
This replaces "cats" with "dogs". Note that "Cats" with capital C is not replaced because replace() is case-sensitive.
Removing Characters
This chains replace() calls to remove all formatting, leaving just "5551234567".
F-Strings
F-strings (formatted string literals) are the modern way to embed expressions inside strings. Prefix the string with f and use curly braces {} to insert values.
This outputs: "My name is Maya and I am 28 years old." The variables are automatically converted to strings inside the {} placeholders.
Expressions in F-Strings
Number Formatting
These print: "$49.50" (2 decimal places), "85.4%" (percentage format), and "1,000,000" (comma separators).
:.2f- 2 decimal places for float:.0f- No decimal places (rounded):,%- Percentage with comma separators:>10- Right-align in 10 character width:08d- Zero-pad integer to 8 digits
- "Hi " + name + "!"
- Must convert numbers
- Hard to read with many values
- f"Hi {name}!"
- Auto-converts types
- Clear and readable
% formatting or .format().String Checking Methods
.isalpha()- All characters are letters.isdigit()- All characters are digits.isalnum()- All characters are letters or digits.isspace()- All characters are whitespace.isupper()- All letters are uppercase.islower()- All letters are lowercase
Practical Validation
> A file is named "report.pdf" and you need to extract just the extension. Pick a slice notation that reliably grabs the last three characters.
filename = "report.pdf" ext = filename print(ext)
Negative slicing with [-n:] reliably extracts the last n characters of any string, regardless of its total length. This makes it more robust than hardcoded index slices like [7:], which break if the string length changes.
> This code uses .replace("cats", "dogs") but only catches the lowercase occurrence. The capitalized "Cats" is left unchanged because replace() is case-sensitive.
Only replaces lowercase "cats", outputting "I like Cats and dogs"
Case sensitivity is one of the most common sources of string comparison bugs. Always normalize user input to a consistent case before comparing or replacing. Calling .lower() before .replace() ensures both "cats" and "Cats" and "CATS" are all matched.
> You are a data engineer at FedEx parsing carrier tracking numbers and address strings from raw API response bodies to extract structured fields for the shipment tracking database.
in locate the delimiter between address components before splitting compound fields into columns.in operator checks if substring exists; .find() returns positionSlice, index, and transform text
- Category
- Python
- Difficulty
- intermediate
- Duration
- 33 minutes
- Challenges
- 0 hands-on challenges
Topics covered: String Indexing, String Slicing, Searching in Strings, String Transformation, F-Strings
Lesson Sections
- String Indexing (concepts: pyStringIndex)
Every character in a string has a position number called an index. Python uses zero-based indexing, meaning the first character is at position 0, not position 1. This prints "P", "y", and "n". The characters are at positions 0, 1, and 5 respectively. Zero-Based Indexing Consider the string "Python". Here's how each character is indexed: The last character's index is always the string length minus 1. For a 6-character string, the last index is 5. Negative Indexing Python has a powerful feature: n
- String Slicing (concepts: pySlicing)
Slicing extracts a portion of a string using the syntax [start:end]. The slice includes the start index but excludes the end index. Slice Defaults Negative Slice Indices Negative indices work in slices too, making it easy to extract from the end: Slice Step A third parameter specifies the step (how many characters to skip):
- Searching in Strings (concepts: pyStringMethods)
Python provides several ways to search for substrings within a string. Each method has specific use cases. The in Operator The first returns True (@ is in the email). The second returns False (gmail is not). find() and index() This finds @ at position 4, then searches for . starting from position 4, finding it at position 12. The count() Method This returns 3 (three a's), 2 (two "na" occurrences), and 0 (no x's). startswith() and endswith() These methods check if a string begins or ends with a s
- String Transformation
Python provides methods to modify strings. Remember: strings are immutable, so these methods return new strings rather than modifying the original. strip(), lstrip(), rstrip() The stripped string is "hello world" with length 11. The original had length 17 including the spaces. You can specify which characters to strip: This removes dollar signs from both ends, giving "99.99". The replace() Method You can limit the number of replacements: This replaces only the first 2 occurrences, giving "1 two
- F-Strings (concepts: pyFStrings)
Expressions in F-Strings You can put any expression inside the curly braces, not just variables: The expressions are evaluated, then the results are inserted into the string. Number Formatting F-strings support format specifications for controlling number display: F-strings have largely replaced concatenation as the preferred approach since Python 3.6. String Checking Methods Python provides methods to check string properties. These all return True or False. The username is alphanumeric (True),