vault backup: 2025-12-11 10:42:22
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m3s
All checks were successful
Deploy Quartz site to GitHub Pages / build (push) Successful in 2m3s
This commit is contained in:
@@ -20,7 +20,7 @@ def find_date(path: Path):
|
||||
def parse_frontmatter(text: str):
|
||||
m = FRONTMATTER_RE.match(text)
|
||||
if not m:
|
||||
return {"tags": [], "date": ""}, text
|
||||
return {"tags": [], "date": "", "maxpoints": ""}, text
|
||||
fm_raw = m.group(1)
|
||||
rest = text[m.end():]
|
||||
tags = []
|
||||
@@ -53,7 +53,12 @@ def parse_frontmatter(text: str):
|
||||
mdate = re.search(r"^date\s*:\s*(.+)$", fm_raw, re.M)
|
||||
if mdate:
|
||||
date_val = mdate.group(1).strip().strip('"\'')
|
||||
return {"tags": tags, "date": date_val}, rest
|
||||
# parse maxpoints (accept either maxpoints or max_points)
|
||||
maxpoints_val = ""
|
||||
mmax = re.search(r"^(?:max_points|maxpoints)\s*:\s*(.+)$", fm_raw, re.M)
|
||||
if mmax:
|
||||
maxpoints_val = mmax.group(1).strip().strip('"\'')
|
||||
return {"tags": tags, "date": date_val, "maxpoints": maxpoints_val}, rest
|
||||
|
||||
def extract_question_answer(body: str):
|
||||
# find first fenced block (prefer spoiler)
|
||||
@@ -75,7 +80,24 @@ def extract_question_answer(body: str):
|
||||
question = body.strip()
|
||||
return question, answer
|
||||
|
||||
def main(root: Path, out: Path):
|
||||
|
||||
def _plain_text_from_md(md_text: str) -> str:
|
||||
"""Simple cleanup to produce plain text from markdown for CSV/Excel export.
|
||||
Removes fenced code blocks, basic markdown punctuation, list markers, and collapses whitespace.
|
||||
This is intentionally lightweight (not a full markdown->text renderer) but good enough for spreadsheet import.
|
||||
"""
|
||||
# remove fenced code blocks
|
||||
txt = re.sub(r"```.*?```", "", md_text, flags=re.S)
|
||||
# remove inline code markers and emphasis/headers
|
||||
txt = re.sub(r"[#*_`]+", "", txt)
|
||||
# remove list markers at start of lines
|
||||
txt = re.sub(r"^\s*-\s+", "", txt, flags=re.M)
|
||||
# collapse whitespace to single spaces
|
||||
txt = re.sub(r"\s+", " ", txt)
|
||||
return txt.strip()
|
||||
|
||||
|
||||
def main(root: Path, out: Path, mode: str = "anki"):
|
||||
rows = []
|
||||
for md in root.rglob("*.md"):
|
||||
# process each markdown file
|
||||
@@ -86,6 +108,7 @@ def main(root: Path, out: Path):
|
||||
date = fm.get("date") or find_date(md.parent)
|
||||
qnum = md.stem
|
||||
tags = fm.get("tags", [])
|
||||
maxpoints = fm.get("maxpoints", "")
|
||||
# choose first tag that's not biokemi or provfråga
|
||||
category = ""
|
||||
for t in tags:
|
||||
@@ -101,6 +124,17 @@ def main(root: Path, out: Path):
|
||||
question_md = question_md.replace("**Rätt svar**", "")
|
||||
question_md = question_md.replace("**Svar**", "")
|
||||
question_md = question_md.replace("**Answer**", "")
|
||||
|
||||
if mode == "excel":
|
||||
# produce plain-text (no HTML) rows: date;question_number;question;category;maxpoints;question;answer
|
||||
date_val = date or ""
|
||||
q_plain = _plain_text_from_md(question_md)
|
||||
a_plain = _plain_text_from_md(answer_md)
|
||||
# columns: date;question_number;question;category;maxpoints;question;answer
|
||||
# move category to be the third column as requested: date;question_number;category;question;maxpoints;question;answer
|
||||
rows.append((date_val, qnum, category, q_plain, maxpoints, q_plain, a_plain))
|
||||
continue
|
||||
|
||||
# Render question and answer markdown to HTML. Enable common extensions.
|
||||
question_html = markdown(question_md, extensions=["fenced_code", "tables"])
|
||||
answer_html = markdown(answer_md, extensions=["fenced_code", "tables"])
|
||||
@@ -116,13 +150,18 @@ def main(root: Path, out: Path):
|
||||
out.parent.mkdir(parents=True, exist_ok=True)
|
||||
with out.open("w", encoding="utf-8", newline="") as f:
|
||||
writer = csv.writer(f, delimiter=";", quoting=csv.QUOTE_ALL)
|
||||
# If exporting for Excel, add a header row matching the columns
|
||||
if mode == "excel":
|
||||
writer.writerow(["date", "question_number", "category", "question", "maxpoints", "question", "answer"])
|
||||
#writer.writerow(["fråga", "svar", "kategori"])
|
||||
for r in rows:
|
||||
writer.writerow(r)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ap = argparse.ArgumentParser(description="Extract questions+answers to CSV")
|
||||
ap.add_argument("root", nargs="?", default="content", help="root content folder (default: content)")
|
||||
ap.add_argument("-o", "--out", default="output.csv", help="output CSV file (default: output.csv)")
|
||||
ap.add_argument("--mode", choices=["anki", "excel"], default="anki", help="output mode: 'anki' (default) or 'excel' (date;question_number;question;category;maxpoints;question;answer)")
|
||||
args = ap.parse_args()
|
||||
main(Path(args.root), Path(args.out))
|
||||
main(Path(args.root), Path(args.out), args.mode)
|
||||
|
||||
Reference in New Issue
Block a user