Quiz 2

Strings — Advanced Methods & Manipulation

2521 words
13 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Strings — Advanced Methods & Manipulation > **Why read this?** Real-world text processing — reading CSV files, parsing user input, cleaning data, extracting information from documents — relies heavily on string methods like `split()`, `join()`, `strip()`, and `replace()`. These are the tools that transform raw tex...

Strings — Advanced Methods & Manipulation

Why read this? Real-world text processing — reading CSV files, parsing user input, cleaning data, extracting information from documents — relies heavily on string methods like split(), join(), strip(), and replace(). These are the tools that transform raw text into usable data. Almost every program deals with text at some point, and mastering these methods separates beginners from competent programmers.

🎯 Learning Objectives

By the end of this topic, you will be able to:
  1. Split strings into lists with split() and rsplit()
  2. Join lists into strings with join()
  3. Strip whitespace and specific characters with strip(), lstrip(), rstrip()
  4. Find and replace substrings with find(), index(), replace()
  5. Check string properties with isalpha(), isdigit(), isalnum(), etc.
  6. Parse structured text like CSV and log files

📋 Prerequisites

  • Strings — Basics & Operations — You need to know about indexing, slicing, and basic string operations.
  • Basic understanding of lists — split() produces lists.

📖 Core Content

18.1 What Problem Do Advanced String Methods Solve?

Intuition: A user submits " John,25,Engineer " in a form. You need to extract the clean name, age, and profession. Raw text from the real world is messy — it has extra spaces, inconsistent formatting, and embedded delimiters. String methods are your cleaning toolkit. Think of a string as a rough block of marble. Methods like strip() chisel away the excess. split() breaks it into pieces. join() reassembles them. replace() swaps out imperfections.

18.2 Splitting Strings: split() and rsplit()

The split() method breaks a string into a list of substrings. By default, it splits on whitespace (spaces, tabs, newlines) and handles multiple spaces gracefully.
python
# runnable
# Default split (any whitespace)
sentence = "Python   is    awesome"
words = sentence.split()
print(words)  # ['Python', 'is', 'awesome']
# Notice: multiple spaces are treated as one separator
# Split with specific separator
data = "apple,banana,cherry,date"
items = data.split(",")
print(items)  # ['apple', 'banana', 'cherry', 'date']
# Limit splits (maxsplit)
text = "one-two-three-four-five"
print(text.split("-", 2))      # ['one', 'two', 'three-four-five']
print(text.rsplit("-", 2))     # ['one-two-three', 'four', 'five']
# Splitlines — split on newlines
multiline = "Line1\nLine2\nLine3"
print(multiline.splitlines())  # ['Line1', 'Line2', 'Line3']
# Practical: parse a colon-separated record
record = "Alice:25:Engineer:New York"
fields = record.split(":")
name, age, job, city = fields
print(f"{name} is {age}, a {job} in {city}")
Output:
pseudo
['Python', 'is', 'awesome']
['apple', 'banana', 'cherry', 'date']
['one', 'two', 'three-four-five']
['one-two-three', 'four', 'five']
['Line1', 'Line2', 'Line3']
Alice is 25, a Engineer in New York

18.3 Joining Strings: join()

The join() method is the inverse of split(). It's called ON the separator string and takes an iterable of strings as argument.
python
# runnable
# Basic join
words = ["Python", "is", "awesome"]
sentence = " ".join(words)
print(sentence)  # "Python is awesome"
# Different separators
fruits = ["apple", "banana", "cherry"]
print(", ".join(fruits))   # "apple, banana, cherry"
print(" - ".join(fruits))  # "apple - banana - cherry"
print("".join(fruits))     # "applebananacherry"
# Join with newline
lines = ["Line 1", "Line 2", "Line 3"]
paragraph = "\n".join(lines)
print(paragraph)
# Practical: reconstruct CSV line
fields = ["Alice", "25", "Engineer"]
csv_line = ",".join(fields)
print(csv_line)  # "Alice,25,Engineer"
Output:
pseudo
Python is awesome
apple, banana, cherry
apple - banana - cherry
applebananacherry
Line 1
Line 2
Line 3
Alice,25,Engineer
⚠️ Common confusion: You write ",".join(list), NOT list.join(","). The separator string is the object; the list is the argument. Think of it as: "Take this separator and put it between each element of the list."

18.4 Stripping Characters: strip(), lstrip(), rstrip()

User input, file data, and web-scraped text often has leading/trailing whitespace or unwanted characters.
python
# runnable
# Whitespace stripping
messy = "  \tHello World  \n"
print(repr(messy.strip()))    # 'Hello World'
print(repr(messy.lstrip()))   # 'Hello World  \n' (left only)
print(repr(messy.rstrip()))   # '  \tHello World' (right only)
# Strip specific characters
text = "---Hello---"
print(text.strip("-"))   # "Hello"
print(text.lstrip("-"))  # "Hello---"
print(text.rstrip("-"))  # "---Hello"
# Multiple characters to strip
url = "www.python.org"
print(url.strip("worg."))  # "python" (strips any of w,o,r,g,.)
# Practical: clean phone number
phone = "+1 (555) 123-4567"
cleaned = phone.strip()
cleaned = cleaned.replace("(", "").replace(")", "").replace("-", "").replace(" ", "")
print(cleaned)  # "+15551234567"
Output:
pseudo
'Hello World'
'Hello World  \n'
'  \tHello World'
Hello
Hello---
---Hello
python
+15551234567

18.5 Finding and Replacing: find(), index(), replace()

python
# runnable
text = "The rain in Spain falls mainly on the plain"
# find() — returns index or -1
print(text.find("rain"))       # 4 (first occurrence starts at index 4)
print(text.find("France"))     # -1 (not found)
print(text.rfind("ain"))       # 40 (last occurrence, search from right)
# index() — like find but raises ValueError if not found
print(text.index("Spain"))     # 12
# print(text.index("France"))  # ValueError!
# replace() — replaces ALL occurrences
print(text.replace("ain", "!!!"))
# "The r!!! in Sp!!! falls m!!!ly on the pl!!!"
# replace with count limit
print(text.replace("ain", "!!!", 2))
# "The r!!! in Sp!!! falls mainly on the plain" (only first 2)
# Chaining methods
cleaned = text.replace("ain", "!!!" ).upper()
print(cleaned)
Output:
pseudo
4
-1
40
12
The r!!! in Sp!!! falls m!!!ly on the pl!!!
The r!!! in Sp!!! falls mainly on the plain
THE R!!! IN SP!!! FALLS M!!!LY ON THE PL!!!

18.6 Character Property Checks

These methods check the CATEGORY of characters in a string and return boolean values.
python
# runnable
print("hello".isalpha())       # True — all letters
print("hello123".isalpha())    # False — has digits
print("123".isdigit())         # True — all digits
print("123.45".isdigit())      # False — has decimal point
print("hello123".isalnum())    # True — alphanumeric
print("hello 123".isalnum())   # False — has space
print("Hello".islower())       # False
print("hello".islower())       # True
print("HELLO".isupper())       # True
print("Hello World".istitle()) # True — each word starts uppercase
print("  ".isspace())          # True — only whitespace
print("".isspace())            # False — empty string
# Practical: strong password checker
password = "Abc123!@"
has_upper = any(c.isupper() for c in password)
has_lower = any(c.islower() for c in password)
has_digit = any(c.isdigit() for c in password)
has_special = any(not c.isalnum() for c in password)
print(f"Strong password: {has_upper and has_lower and has_digit and has_special}")
Output:
pseudo
True
False
True
False
True
False
False
True
True
True
True
False
Strong password: True

18.7 Worked Example 1: CSV Parsing (Complete)

Let's parse a multi-line CSV string and extract structured data:
python
# runnable
csv_data = """Name,Age,City,Salary
Alice,25,New York,60000
Bob,30,Los Angeles,75000
Charlie,22,Chicago,45000
Diana,28,Boston,82000"""
# Parse manually
lines = csv_data.strip().split("\n")
header = lines[0].split(",")
print("Header:", header)
# Create a list of dictionaries
employees = []
for line in lines[1:]:
    values = line.split(",")
    employee = {
        "name": values[0],
        "age": int(values[1]),
        "city": values[2],
        "salary": int(values[3])
    }
    employees.append(employee)
# Display summary
for emp in employees:
    print(f"{emp['name']:10} | {emp['age']:3} | {emp['city']:15} | ₹{emp['salary']:,}")
# Compute average salary
avg_salary = sum(e["salary"] for e in employees) / len(employees)
print(f"\nAverage salary: ₹{avg_salary:,.0f}")
Output:
pseudo
Header: ['Name', 'Age', 'City', 'Salary']
Alice      |  25 | New York        | ₹60,000
Bob        |  30 | Los Angeles     | ₹75,000
Charlie    |  22 | Chicago         | ₹45,000
Diana      |  28 | Boston          | ₹82,000
Average salary: ₹65,500

18.8 Worked Example 2: Log File Parser

Parse server log entries to extract IP addresses and error types:
python
# runnable
log_text = """192.168.1.1 - - [01/Mar/2024:12:00:01] "GET /index.html" 200
192.168.1.2 - - [01/Mar/2024:12:00:05] "POST /login" 401
192.168.1.1 - - [01/Mar/2024:12:00:10] "GET /dashboard" 500
192.168.1.3 - - [01/Mar/2024:12:00:15] "GET /index.html" 200"""
logs = log_text.strip().split("\n")
errors = []
for entry in logs:
    parts = entry.split()
    ip = parts[0]
    method = parts[5].strip('"')
    path = parts[6]
    status = int(parts[8])
    if status >= 400:
        errors.append(f"ERROR: {ip} - {method} {path} -> {status}")
print("Errors found:")
for err in errors:
    print(f"  {err}")
Output:
pseudo
Errors found:
  ERROR: 192.168.1.2 - POST /login -> 401
  ERROR: 192.168.1.1 - GET /dashboard -> 500

18.9 Worked Example 3: Text Cleaner Function

python
# runnable
def clean_text(text):
    """Clean and normalize text."""
    # Strip leading/trailing whitespace
    text = text.strip()
    # Remove extra internal spaces
    text = " ".join(text.split())
    # Remove special characters (keep letters, spaces, basic punctuation)
    cleaned = ""
    for ch in text:
        if ch.isalnum() or ch in " .,!?'-":
            cleaned += ch
    return cleaned
# Test
dirty = "  Hello!!!   This  is   a  MESSY   string...   with   extra spaces!!  "
clean = clean_text(dirty)
print(f"Original: '{dirty}'")
print(f"Cleaned:  '{clean}'")
# Sentence capitalization
sentences = clean.split(".")
cap_sentences = [s.strip().capitalize() for s in sentences if s.strip()]
final = ". ".join(cap_sentences) + "."
print(f"Final:    '{final}'")
Output:
pseudo
Original: '  Hello!!!   This  is   a  MESSY   string...   with   extra spaces!!  '
Cleaned:  'Hello This is a MESSY string with extra spaces'
Final:    'Hello. This is a messy string. With extra spaces'

18.10 Worked Example 4: Finding Email Addresses

python
# runnable
text = """Contact us at support@example.com or sales@company.org.
For personal inquiries, reach john.doe@gmail.com or jane_smith@yahoo.co.uk.
Our internal server is admin@localhost (local only)."""
# Simple email finder
words = text.split()
emails = []
for word in words:
    word = word.strip(".,!?;:()")
    if "@" in word and "." in word.split("@")[1]:
        emails.append(word.lower())
print("Found email addresses:")
for email in emails:
    username, domain = email.split("@")
    print(f"  User: {username:20} | Domain: {domain}")
Output:
pseudo
Found email addresses:
  User: support              | Domain: example.com
  User: sales                | Domain: company.org
  User: john.doe             | Domain: gmail.com
  User: jane_smith           | Domain: yahoo.co.uk
  User: admin                | Domain: localhost

18.11 Worked Example 5: URL Parameter Parser

python
# runnable
url = "https://example.com/search?q=python+tutorial&page=2&sort=recent&lang=en"
# Extract query string
query_start = url.find("?")
if query_start != -1:
    query_string = url[query_start + 1:]
    params = query_string.split("&")
    print("URL Parameters:")
    for param in params:
        key, value = param.split("=")
        value = value.replace("+", " ")
        print(f"  {key:10} = {value}")
Output:
pseudo
URL Parameters:
  q          = python tutorial
  page       = 2
  sort       = recent
  lang       = en

📐 Key Concepts Reference

MethodPurposeExampleResult
split()Split on whitespace"a b".split()['a', 'b']
split(sep)Split on separator"a,b".split(",")['a', 'b']
rsplit(sep, n)Split from right"a-b-c".rsplit("-",1)['a-b', 'c']
join(iter)Join with separator",".join(["a","b"])"a,b"
strip()Remove leading/trailing whitespace" a ".strip()"a"
strip(chars)Remove specific chars"--a--".strip("-")"a"
find(sub)Find first index or -1"abc".find("b")1
rfind(sub)Find last index"aba".rfind("a")2
index(sub)Find or raise error"abc".index("b")1
replace(old, new)Replace all"a-a".replace("-","+")"a+a"
isalpha()All letters?"abc".isalpha()True
isdigit()All digits?"123".isdigit()True
isalnum()Letters and/or digits?"ab3".isalnum()True
islower()All lowercase?"abc".islower()True
isupper()All uppercase?"ABC".isupper()True
istitle()Title case?"Hello World".istitle()True

⚠️ Common Pitfalls

Pitfall 1: split() Without Arguments vs With ' '

The mistake: data = "a b c"data.split() returns ['a', 'b', 'c'] (handles multiple spaces). But data.split(" ") returns ['a', '', 'b', '', 'c'] (empty strings between double spaces). Why: Default split() treats any whitespace as a single delimiter. Explicit " " treats each space character as a separate delimiter. Fix: Use default split() for natural text. Use explicit split(" ") only when you need to preserve empty fields.

Pitfall 2: join() Called on Wrong Object

The mistake: ["a", "b"].join(",") Error: AttributeError: 'list' object has no attribute 'join' Why: join() is a method of strings, not lists. The separator is the object. Fix: ",".join(["a", "b"]) — the separator string comes first.

Pitfall 3: find() Return of 0 is Falsy

The mistake: if text.find("start"): — this is False when "start" is found at position 0! Why: find() returns index 0 when found at the beginning. 0 is falsy in Python. Fix: Use if "start" in text: for boolean membership, or if text.find("start") != -1:.

Pitfall 4: replace() Doesn't Modify In-Place

The mistake: text.replace("a", "b") then printing text — it's unchanged! Why: Strings are immutable. replace() returns a NEW string. Fix: Assign the result: text = text.replace("a", "b").

Pitfall 5: .strip() Removes Any Characters in the Set

The mistake: "hello.py".strip(".py") expecting "hello" but getting "hello.". Why: strip(".py") removes ANY of the characters ., p, y from both ends. It's not a substring removal, it's a character set. Fix: For removing extensions, use rsplit(".", 1)[0] or removesuffix() (Python 3.9+).

📝 Practice Questions

Q1: What does " Hello World ".split() return?
Answer: ['Hello', 'World'] — default split handles multiple spaces as one delimiter and strips leading/trailing whitespace. Q2: What's the output of ",".join(["a", "b", "c"])?
Answer: "a,b,c" — joins elements with comma between them. Q3: What's wrong with ["a","b"].join(",")?
Answer: Lists don't have a join() method. It should be ",".join(["a", "b"])join() is a string method called on the separator. Q4: Given the string "user:alice:pass:secret123:role:admin", extract the username and role.
Answer:
python
# runnable
data = "user:alice:pass:secret123:role:admin"
parts = data.split(":")
username = parts[1]
role = parts[5]
print(f"Username: {username}, Role: {role}")
Q5: Write a function that takes a filename like "document.pdf" and returns the extension.
Answer:
python
# runnable
def get_extension(filename):
    parts = filename.rsplit(".", 1)
    if len(parts) > 1:
        return parts[1]
    return ""

print(get_extension("document.pdf"))   # pdf
print(get_extension("archive.tar.gz")) # gz (rsplit gives last one)
print(get_extension("README"))          # (empty)
Q6: How does " abc ".strip() differ from " abc ".replace(" ", "")?
Answer:
  • strip() removes only leading and trailing whitespace → "abc"
  • replace(" ", "") removes ALL spaces including internal ones → "abc" (same here, but different if there were internal spaces)
For " a b c ":
  • strip()"a b c" (internal space preserved)
  • replace(" ", "")"abc" (all spaces removed) Q7: Parse the following log line and extract the IP address and status code:
pseudo
192.168.1.1 - - [01/Mar/2024:12:00:01] "GET /index.html" 200
Answer:
python
# runnable
line = '192.168.1.1 - - [01/Mar/2024:12:00:01] "GET /index.html" 200'
parts = line.split()
ip = parts[0]
status = int(parts[8])
print(f"IP: {ip}, Status: {status}")
Q8: Write a function that converts a string to snake_case (e.g., "Hello World" → "hello_world").
Answer:
python
# runnable
def to_snake_case(text):
    text = text.strip().lower()
    words = text.split()
    return "_".join(words)

print(to_snake_case("Hello World"))           # hello_world
print(to_snake_case("  Python  Programming  ")) # python_programming
print(to_snake_case("userName"))               # username (no spaces to split)
# Advanced version that handles camelCase:
import re
def to_snake_case_advanced(text):
    text = re.sub(r'([A-Z])', r'_\1', text).lower().strip('_')
    return "_".join(text.split())

print(to_snake_case_advanced("userName"))      # user_name
Q9: What does "123abc".isalnum() return? What about "123".isalpha()?
Answer:
  • "123abc".isalnum()True (all characters are alphanumeric)
  • "123".isalpha()False (digits 1,2,3 are not alphabetic)
  • "abc".isdigit()False (letters are not digits) Q10: Write code to extract all hashtags from a tweet string.
Answer:
python
# runnable
tweet = "Just finished #Python course! Excited to learn #DataScience and #MachineLearning next! #coding"
words = tweet.split()
hashtags = [word for word in words if word.startswith("#")]
# Clean the hashtags
hashtags = [h.strip("!?.,;:") for h in hashtags]
print(f"Hashtags found: {hashtags}")

🔗 Cross-References

  • Next Topic: Dictionaries — Storing key-value data, often used with parsed string data.
  • Previous Topic: Sets — Unordered collections for membership testing.
  • BSCS1001 Computational Thinking: String parsing is a fundamental algorithmic pattern — tokenization.
  • Reference: Python for Everybody, Chapter 6 (Sections 6.9-6.10) — "String methods" and "Parsing strings"
  • Video: L17: Mastering string methods in python, L20: An interesting cipher (more on strings) Join Discord Previous17. SetsNext19. Dictionaries
Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.