String methods and formatting
The full string toolkit: case, search, split and join, replace, padding, and f-string format specifiers.
Why this matters in AI / ML / GenAI
Cleaning documents before embedding, normalising labels, parsing model output, and printing readable metrics are all string work. f-string format specifiers are how you produce log lines and reports that people can actually scan.
1. Read
Understand the idea in plain English first.
2. Run
Load any example into the compiler and press Run.
3. Change
Edit one value, rerun, and learn from the output.
The method groups
Strings are immutable — every method returns a new string. Assign the result.
Case: lower, upper, title, capitalize, swapcase, casefold (aggressive lowercase for comparisons across languages).
Whitespace: strip, lstrip, rstrip — pass characters to strip something specific, e.g. strip(".,").
Search: find (-1 if absent), index (raises), count, startswith, endswith, and the in operator.
Split and join: split, rsplit, splitlines, partition, and "sep".join(list).
Transform: replace, removeprefix, removesuffix, zfill, ljust, rjust, center.
Tests: isdigit, isalpha, isalnum, isspace, islower, isupper.
Note "".join(parts) is dramatically faster than repeated += in a loop, because each += allocates a whole new string.
Format specifiers
Inside an f-string, everything after : is a format specification.
| Spec | Meaning | Example output |
|---|---|---|
:.2f | 2 decimal places | 0.91 |
:.1% | percentage | 91.3% |
:, | thousands separator | 1,234,567 |
:>10 | right align, width 10 | hello |
:<10 | left align | hello |
:^10 | centre | hello |
:08.3f | zero-pad, 3 decimals | 0004.500 |
:e | scientific | 2.000000e-05 |
:+ | always show sign | +5 |
{value!r} inserts repr(value) instead of str(value) — it shows quotes and escapes, which is what you want in logs and error messages.
{name=} prints both the expression and its value: f"{lr=}" gives lr=2e-05. Excellent for quick debugging.
Multi-line text and escapes
Triple quotes preserve newlines and are the natural home for prompt templates.
textwrap.dedent strips the common leading indentation, so an indented triple-quoted string inside a function does not carry the code's indentation into the prompt.
Escapes: \n newline, \t tab, \\ backslash, \" quote.
Raw strings (r"...") disable escapes and are required for regular expression patterns and Windows paths.
Hands-on practice
Compiler on the left. Examples on the right.
On desktop, keep the compiler beside the examples. On mobile, the same blocks stack cleanly. Pick an example, try it in the compiler, then change one small thing.
Normalise and report on documents
Live Python compiler
Try it — in-browser Python
Add a document with mixed case and extra spaces, then check the summary table.
Code editor
Output
Python runs in your browser. First run downloads the runtime.
Press Run (or Ctrl+Enter) to execute.
Runs CPython in your browser. NumPy, pandas, scikit-learn and Matplotlib load on demand. Charts appear below the output. No input(), no GPU, no network installs.
Clear code examples
Every example is copy-ready. Use Try in compiler when you want to experiment without scrolling around.
Example
Cleaning a document
The normalisation pipeline you run before embedding text.
raw = " The QUICK brown Fox...\n\n jumped! "
step1 = raw.strip()
step2 = step1.lower()
step3 = " ".join(step2.split()) # collapse all whitespace
step4 = step3.replace("...", ".").strip(".!")
print(repr(raw))
print(repr(step1))
print(repr(step3))
print(repr(step4))
print("words:", len(step4.split()))
print("title case:", step4.title())Example
Search, split, and join
partition is useful for splitting on the first separator only.
line = "2026-09-04 ERROR model=gpt-4.1-mini latency_ms=2450"
print("starts with date:", line.startswith("2026"))
print("contains ERROR :", "ERROR" in line)
print("position of 'model':", line.find("model"))
print("count of '=' :", line.count("="))
parts = line.split()
print("fields:", parts)
fields = {}
for token in parts:
if "=" in token:
key, _, value = token.partition("=")
fields[key] = value
print("parsed:", fields)
print("rejoined:", " | ".join(parts[:3]))Example
Format specifiers in a metrics table
Alignment and precision turn output into a readable report.
rows = [
("gpt-4.1-mini", 0.913, 128, 0.000372),
("llama-3-8b", 0.8471, 1520, 0.0),
("claude-haiku", 0.9002, 460, 0.00124),
]
print(f"{'model':<15}{'accuracy':>10}{'latency':>10}{'cost':>12}")
print("-" * 47)
for name, acc, latency, cost in rows:
print(f"{name:<15}{acc:>9.1%}{latency:>9,d}ms${cost:>11.6f}")
lr = 2e-5
print(f"\ndebug style: {lr=}")
print(f"repr style : {'text with \"quotes\"'!r}")
print(f"sign : {5:+d} {-5:+d}")
print(f"zero pad : {7:03d}")Example
Multi-line prompts with dedent
dedent keeps the prompt clean even when the code is indented.
import textwrap
def build_prompt(question, context):
template = """
You are a precise assistant.
Use only the context below.
Context:
{context}
Question: {question}
"""
return textwrap.dedent(template).strip().format(context=context, question=question)
print(build_prompt("What is RAG?", "RAG retrieves documents, then generates."))
print("---")
print("raw string for regex:", r"\d+\.\d+")Example
Why join beats += in a loop
Each += builds a whole new string; join allocates once.
import time
words = [f"token{i}" for i in range(20_000)]
start = time.perf_counter()
acc = ""
for w in words:
acc += w + " "
concat_ms = (time.perf_counter() - start) * 1000
start = time.perf_counter()
joined = " ".join(words) + " "
join_ms = (time.perf_counter() - start) * 1000
print(f"+= in loop : {concat_ms:7.2f} ms")
print(f"str.join : {join_ms:7.2f} ms")
print("same result:", acc == joined)Takeaways
- String methods return new strings — always assign the result.
- Use "".join(list) instead of += inside a loop.
- Format specifiers (:.2f, :.1%, :>10, !r, =) turn raw values into readable reports.