learning-website-framework1-3 Exercise 1: Read the Banner =========================================================== Write parse_banner(text), which returns a dictionary describing a page from its opening comment (or its , for a full HTML page). It must cope with every banner shape that really exists on this site. Save as banner.py: import json, os, re, sys KEY = re.compile(r"^([A-Za-z][A-Za-z ]*?):\s*(.*)$") DATES = re.compile(r"Date Created:\s*(\d{4}-\d{2}-\d{2})\s+Date Updated:\s*(\d{4}-\d{2}-\d{2})") def parse_banner(text): """Return a dict describing the page, from its banner comment or <title>.""" if text.lstrip().lower().startswith("<!doctype"): m = re.search(r"<title>(.*?)", text, re.S) return {"kind": "full-page", "title": m.group(1).strip() if m else None} m = re.match(r"\s*", text, re.S) if not m: return {"kind": "no-banner"} block = m.group(1) info = {} d = DATES.search(block) if d: info["created"], info["updated"] = d.group(1), d.group(2) lines = [ln.strip().strip("=").strip() for ln in block.splitlines()] lines = [ln for ln in lines if ln] for ln in lines: km = KEY.match(ln) if not km: continue key, value = km.group(1).strip(), km.group(2).strip() if key in ("Date Created", "Date Updated"): continue info.setdefault(key.lower(), value) if "course" in info: info["kind"] = "course-chapter" elif "category" in info: info["kind"] = "sidebar" else: # free-form banner such as "PYTHON LESSON: Boolean Logic ..." headline = lines[0] if lines else "" info["kind"] = "free-banner" info["headline"] = headline return info if __name__ == "__main__": root = sys.argv[1] for rel in sys.argv[2:]: with open(os.path.join(root, rel), encoding="utf-8") as fh: head = fh.read(4000) info = parse_banner(head) info = {k: (v[:70] + "...") if isinstance(v, str) and len(v) > 70 else v for k, v in info.items()} print(rel) print(" " + json.dumps(info, ensure_ascii=False)) Run it (the first argument is your content/ folder): python banner.py "/claude-projects/website-content/content" hungary/hungarian-basic-3/hungarian_basic_conversation_3_1.html sidebar/programming/cheat_sheet_git_command_line.html ... Output (checked by running it on real files): hungary/hungarian-basic-3/hungarian_basic_conversation_3_1.html {"created": "2026-10-05", "updated": "2026-10-05", "course": "Hungarian Basic Conversation 3", "chapter": "Buying Clothes: Sizes, Fit & Returns", "file": "hungarian_basic_conversation_3_1.html", "topic": "Buying clothes: clothes and colour words, sizes and fit, Felpróbálhato...", "level": "Elementary | Hungarian + English respelling", "kind": "course-chapter"} sidebar/programming/cheat_sheet_git_command_line.html {"created": "2026-10-06", "updated": "2026-10-06", "category": "Sidebar", "subcategory": "Programming", "chapter": "Git Command Line Cheat Sheet", "file": "cheat_sheet_git_command_line.html", "kind": "sidebar"} web-servers/apache-in-depth/apache_in_depth_1_1.html {"course": "Apache In Depth", "chapter": "Scope: What This Course Builds On, and Why It's Apache-Only", "file": "apache_in_depth_1_1.html", "topic": "Recapping exactly what Web Servers Fundamentals left deliberately shal...", "kind": "course-chapter"} programming/general-purpose-languages/python/python-lessons/python_lesson_boolean_logic_truthy_falsy.html {"created": "2026-08-16", "updated": "2026-08-16", "python lesson": "Boolean Logic — What Python Actually Considers True or False", "level": "Beginner Python / Experienced Programmer", "kind": "free-banner", "headline": "PYTHON LESSON: Boolean Logic — What Python Actually Considers True or ..."} hungary/hungarian-lessons/hungarian_alphabet.html {"level": "All levels (pronunciation guide & letter reference)", "focus": "All 44 Hungarian letters (14 vowels + 30 consonants/digraphs)", "kind": "free-banner", "headline": "HUNGARIAN ALPHABET REFERENCE"} japan/japanese-language/reference-materials/kanji/kanji_上.html {"kind": "full-page", "title": "上 | Kanji | osztromok.com"} The shapes found ---------------- 1. course-chapter: Course / Chapter / File / Topic (+ dates when present; older courses such as Apache In Depth have none) 2. sidebar: Category / Subcategory / Chapter / File (+ dates) 3. free-banner: a headline such as "PYTHON LESSON: ..." with Level and dates 4. free-banner without a title: the Hungarian alphabet reference 5. full-page: a complete HTML page with no banner (the kanji pages), where the title comes from WHY THIS WORKS AS AN ANSWER --------------------------- The site's files are the database. A parser that reads the banner gives the build the same information a CMS would store in columns: the course, the chapter title, the dates. Handling every shape up front (instead of assuming the newest one) is what lets old and new content share one site. Returning a "kind" lets later code decide how to treat each page, and returning only what is actually present (note the Apache chapter has no dates) means missing data shows up as missing rather than being invented.