Day 8 – String Manipulation and Formatting
๐งต Day 8 – String Manipulation and Formatting
1. Learning Objectives
By the end of Day 8, you will be able to:
- Use common string methods (
.upper(),.lower(),.strip(),.split(),.join(),.replace(),.find(),.startswith()). - Format strings using f‑strings,
.format(), and%‑formatting. - Generate formatted reports (e.g., material take‑offs, beam schedules).
- Work with part marks, drawing numbers, and naming conventions.
- Clean and standardise user‑input strings for robust AEC scripts.
2. Concept Explanation
2.1 Why Strings Matter in AEC
Strings are everywhere in AEC practice:
- Drawing numbers:
"A-101","S-202-RevB" - Material names:
"Concrete C30","Steel Grade 355" - Part marks:
"UB 406×178×60","B1","COL-12" - Project codes:
"PROJ-2026-045" - User input that needs cleaning (e.g.,
" Concrete "→"Concrete")
Being able to manipulate and format strings is essential for generating professional output and parsing data from external sources.
2.2 Common String Methods
| Method | Description | AEC Example |
|---|---|---|
.upper() | Convert to uppercase | "beam".upper() → "BEAM" |
.lower() | Convert to lowercase | "STEEL".lower() → "steel" |
.strip() | Remove leading/trailing whitespace | " Concrete ".strip() → "Concrete" |
.split(sep) | Split into list by separator | "UB 406×178×60".split("×") → ['UB 406', '178', '60'] |
.join(iterable) | Join list elements into string | "-".join(["A","101"]) → "A-101" |
.replace(old,new) | Replace all occurrences | "S-201".replace("-","/") → "S/201" |
.find(sub) | Return index of first occurrence (-1 if not found) | "Concrete C30".find("C30") → 9 |
.startswith(pre) | Check if string starts with prefix | "S-202".startswith("S") → True |
.endswith(suf) | Check if string ends with suffix | "drawing.pdf".endswith(".pdf") → True |
2.3 String Formatting Options
f‑strings (Python 3.6+, recommended)
beam_mark = "B1"
span = 6.0
load = 25.0
print(f"Beam {beam_mark}: span = {span:.1f} m, load = {load:.1f} kN/m")
.format() method
print("Beam {}: span = {:.1f} m, load = {:.1f} kN/m".format(beam_mark, span, load))
%‑formatting (older style)
print("Beam %s: span = %.1f m, load = %.1f kN/m" % (beam_mark, span, load))
Alignment and width specifiers (f‑string):
# Left (<), Right (>), Center (^)
print(f"{'Mark':<10} {'Span':>8} {'Load':>8}")
print(f"{'B1':<10} {6.0:>8.1f} {25.0:>8.1f}")
3. Code Examples
Example 1: Standardising material names from user input
# User might type "concrete", "Concrete", " CONCRETE " etc.
raw_material = input("Enter material type: ")
clean_material = raw_material.strip().lower()
print(f"Standardised: {clean_material}")
# Check against known materials
known_materials = ["concrete", "steel", "timber", "masonry"]
if clean_material in known_materials:
print("Valid material.")
else:
print("Unknown material – please check specification.")
Example 2: Parsing a beam mark into components
# Typical beam mark format: "B-01", "B-12", "B1" – but can vary
beam_mark = "B1-12"
# Split by '-' or use indexing
parts = beam_mark.split("-")
print(parts) # ['B1', '12'] if hyphen present
# More robust parsing
if "-" in beam_mark:
prefix, number = beam_mark.split("-")
else:
prefix = beam_mark[0]
number = beam_mark[1:]
print(f"Prefix: {prefix}, Number: {number}")
Example 3: Generating a formatted beam schedule
beams = [
{"mark": "B1", "span": 6.0, "load": 25, "depth": 400},
{"mark": "B2", "span": 4.5, "load": 18, "depth": 350},
{"mark": "B3", "span": 7.2, "load": 30, "depth": 500},
]
# Column headers with alignment
print(f"{'Beam':<8} {'Span (m)':<10} {'Load (kN/m)':<12} {'Depth (mm)':<10}")
print("-" * 40)
for b in beams:
print(f"{b['mark']:<8} {b['span']:<10.1f} {b['load']:<12.1f} {b['depth']:<10}")
Output:
Beam Span (m) Load (kN/m) Depth (mm)
----------------------------------------
B1 6.0 25.0 400
B2 4.5 18.0 350
B3 7.2 30.0 500
Example 4: Working with drawing number revisions
# Drawing register management
drawing = "S-202-RevB"
# Check discipline
if drawing.startswith("S-"):
discipline = "Structural"
elif drawing.startswith("A-"):
discipline = "Architectural"
elif drawing.startswith("M-"):
discipline = "Mechanical"
elif drawing.startswith("E-"):
discipline = "Electrical"
else:
discipline = "Unknown"
print(f"Drawing {drawing} → Discipline: {discipline}")
# Extract revision
if "Rev" in drawing:
parts = drawing.split("Rev")
rev_letter = parts[-1]
print(f"Revision: {rev_letter}")
else:
print("No revision found")
Example 5: Building a part mark from components
# Generate a standard steel member tag
member_type = "UB"
depth = 406
weight = 60
length = 8.5
# Format: "UB-406x178x60-L=8.5m"
part_mark = f"{member_type}-{depth}x178x{weight}-L={length}m"
print(part_mark) # "UB-406x178x60-L=8.5m"
# Or with padding for a table
print(f"{member_type:<4} {depth:>4} x 178 x {weight:<4} L = {length:.1f} m")
4. Hands‑on Exercises (3–5 Problems)
Problem 1 – Name cleaning
Ask the user to enter a material name (e.g., " ConCrete ").
Use .strip().lower() to clean it, then check if it's in a list of acceptable materials. Print appropriate messages.
Problem 2 – Drawing number parser
Given a drawing number like "STR-101-RevC", write code that:
- Extracts the discipline prefix (
"STR") - Extracts the number (
"101") - Extracts the revision (
"C") - Prints each part on a separate line.
Hint: use .split("-").
Problem 3 – Formatted quantity take‑off
You have a list of dictionaries representing material quantities:
materials = [
{"name": "Concrete C30", "volume": 45.2, "unit": "m³"},
{"name": "Rebar 20mm", "mass": 12.5, "unit": "tonnes"},
{"name": "Steel UB 406", "mass": 8.3, "unit": "tonnes"},
]
Print a nicely formatted table with aligned columns:
Material Quantity Unit
----------------------------------------
Concrete C30 45.20 m³
Rebar 20mm 12.50 tonnes
Steel UB 406 8.30 tonnes
Problem 4 – Joining floor names
You have a list of floor names: ["Ground", "Level 2", "Level 3", "Roof"].
Use .join() to create a single string: "Ground | Level 2 | Level 3 | Roof".
Then replace "Level " with "L" using .replace() to get: "Ground | L2 | L3 | Roof".
Solutions (attempt first):
# P1
acceptable = ["concrete", "steel", "timber", "masonry"]
raw = input("Enter material: ")
clean = raw.strip().lower()
if clean in acceptable:
print(f"{clean} is accepted.")
else:
print(f"{clean} is not in the approved list.")
# P2
drawing = "STR-101-RevC"
parts = drawing.split("-")
discipline = parts[0]
number = parts[1]
revision = parts[2].replace("Rev", "")
print(f"Discipline: {discipline}")
print(f"Number: {number}")
print(f"Revision: {revision}")
# P3
materials = [
{"name": "Concrete C30", "volume": 45.2, "unit": "m³"},
{"name": "Rebar 20mm", "mass": 12.5, "unit": "tonnes"},
{"name": "Steel UB 406", "mass": 8.3, "unit": "tonnes"},
]
print(f"{'Material':<20} {'Quantity':<10} {'Unit':<10}")
print("-" * 40)
for m in materials:
qty = m.get("volume") or m.get("mass")
print(f"{m['name']:<20} {qty:<10.2f} {m['unit']:<10}")
# P4
floors = ["Ground", "Level 2", "Level 3", "Roof"]
combined = " | ".join(floors)
print(combined)
short = combined.replace("Level ", "L")
print(short)
5. Applied Challenge Task
Task: Drawing Register & Report Generator
You are given a raw list of drawing information as strings:
raw_drawings = [
"A-101-Ground Floor Plan",
"S-201-Foundation Plan-RevB",
"M-301-HVAC Layout",
"E-401-Lighting Plan",
"S-202-First Floor Framing-RevA",
"A-102-First Floor Plan",
]
Write a script that:
Parses each string into components:
- Discipline (first character or prefix)
- Drawing number
- Title
- Revision (if present, e.g.,
"RevB","RevA")
Stores the data in a list of dictionaries with keys:
discipline,number,title,revision.Prints a formatted register table with columns:
Discipline,Number,Title,Revision.Counts how many drawings belong to each discipline (using a dictionary).
Lists all unique revision letters found.
Bonus:
Allow the user to filter by discipline: e.g., input "S" and show only structural drawings.
Why this matters:
This task mimics real‑world document management in AEC projects. You'll use string splitting, joining, formatting, and dictionary accumulation – all essential for handling project data.
6. Brief Review Summary
- String methods:
.strip(),.lower(),.upper(),.split(),.join(),.replace(),.startswith(),.find(). - f‑strings:
f"{value:width.precision}"for aligned, formatted output. .format()and%formatting are alternatives.- Clean user input before processing (strip + lower).
- Parsing structured strings (e.g., drawing numbers) is a common AEC task.
- Formatted tables improve readability of reports.
Key takeaway:
String manipulation turns messy, human‑generated data into clean, structured information you can process and present professionally – an essential skill for any AEC automation workflow.
7. Preview of Next Topic (Day 9)
Tomorrow we’ll cover File Handling – Reading/Writing CSV, TXT, and Excel files (pandas introduction).
You’ll learn:
- Opening and reading text files (
.txt,.csv). - Writing reports to files.
- Introduction to pandas for reading/writing Excel spreadsheets.
- Practical example: reading a table of structural members from a CSV and performing calculations.
File I/O is what connects your Python scripts to real project data – you'll be able to import existing schedules and export results.

Comments
Post a Comment