9.16 Hands-on Exercises
Practice programs reinforcing Python string concepts -- a log-level analyzer, an IP address extractor, a config file parser, and a password strength checker.
Log Level Analyzer
Build a function that scans a batch of log lines and tallies how many fall into each severity level — an at-a-glance health summary without opening a log viewer.
import re
from collections import Counter
def analyze_log_levels(lines):
levels = [re.search(r"\b(INFO|WARNING|ERROR)\b", l).group(1) for l in lines]
return dict(Counter(levels))
>>> analyze_log_levels([
... "2026-07-13 10:00:01 INFO Service started",
... "2026-07-13 10:00:05 ERROR Connection refused",
... "2026-07-13 10:00:07 WARNING High memory usage",
... ])
{'INFO': 1, 'ERROR': 1, 'WARNING': 1}
IP Address Extractor
Pull every IPv4 address out of free-form text — the first step in building a blocklist, an allowlist audit, or a geo-lookup report from security logs.
>>> text = "Connections from 192.168.1.10 and 10.0.0.5 were blocked; 8.8.8.8 allowed"
>>> re.findall(r"\b(?:\d{1,3}\.){3}\d{1,3}\b", text)
['192.168.1.10', '10.0.0.5', '8.8.8.8']
Configuration File Parser
Read a simple key=value config format, with comment lines starting with # — a recurring task for any tool that needs its own settings file without pulling in a full config-parsing library.
def parse_config(text):
result = {}
for line in text.splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
key, _, value = line.partition("=")
result[key] = value
return result
>>> parse_config("# config\nhost=localhost\nport=8080\n\ndebug=true")
{'host': 'localhost', 'port': '8080', 'debug': 'true'}
Password Strength Checker
Enforce a minimum length plus a mix of character classes — a standard first line of defense against weak passwords during account signup.
def is_strong_password(pw):
if len(pw) < 8:
return False
has_upper = any(c.isupper() for c in pw)
has_lower = any(c.islower() for c in pw)
has_digit = any(c.isdigit() for c in pw)
has_special = any(not c.isalnum() for c in pw)
return all([has_upper, has_lower, has_digit, has_special])
>>> is_strong_password("Weak1")
False
>>> is_strong_password("Str0ng!Pass")
True
Mini Projects
- DevOps health report generator — turn raw HTTP status-code counts into a single human-readable error-rate line (
"1000 requests, 2.0% error rate"), reusingCounterfrom earlier in this chapter. - CI/CD build summarizer — parse a Jenkins-style console line (
"Build #42 SUCCESS in 3m 15s") into a structured{"build", "status", "duration"}result, ready to feed a Slack notification. - Kubernetes log analyzer — combine the pod-name parser from 9.12 Strings in DevOps and AWS with the log-level counter above to produce a per-deployment error-rate summary.
Quick Interview Answer
“These exercises tie the chapter’s tools together: the log analyzer combines regex extraction with
Counter; the IP extractor is a single well-chosen regex; the config parser leans onpartition()instead of a fragile manual split; and the password checker chains severalis*validation methods withany(). The common thread is picking the right existing tool — regex,Counter,partition,is*— over hand-rolled character-by-character logic.”
Common Mistakes
- Using
split("=")instead ofpartition("=")in the config parser —split()breaks on a value that itself contains an=character, whilepartition()splits only on the first occurrence. - Forgetting the password checker’s
has_specialcheck needsnot c.isalnum(), not a hardcoded set of symbols, so it correctly accepts any real special character. - Letting one malformed log line crash the whole analyzer instead of skipping or flagging lines that don’t match the expected pattern (
re.search(...)returningNone).
Add More Questions to This Guide
Know a question that should be here? Share it and help the community!
Open Google Form