import csv import re import subprocess import sys from pathlib import Path # extract transaction from izpisek pdf TRANSACTION_START = re.compile(r"^\d{2}\.\d{2}\.\d{2}\s") TRANSACTION_LINE = re.compile( r"^(?P\d{2}\.\d{2}\.\d{2})\s+" r"(?P.*?)\s+" r"(?P[+-][\d.,]+)\s+" r"(?P-?[\d.,]+-?)\s*$" ) CONTINUATION_INDENT = 15 FIELD_SPLIT = re.compile(r"\s{4,}") ACCOUNT = re.compile(r"^SI\d{2}(?:\s?\d{4}){3}\s?\d{3}$") def pdf_to_text(pdf_path): result = subprocess.run( ["pdftotext", "-layout", str(pdf_path), "-"], capture_output=True, text=True, check=True, ) return result.stdout def parse_transaction(line): m = TRANSACTION_LINE.match(line.rstrip()) account = "" desc_parts = [] for f in FIELD_SPLIT.split(m.group("middle").strip()): if ACCOUNT.match(f): account = f else: desc_parts.append(f) balance = m.group("balance") if balance.endswith("-"): balance = "-" + balance[:-1] return { "date": m.group("date"), "desc": " ".join(desc_parts), "account": account, "amount": m.group("amount"), "balance": balance, "currency": "EUR", } def extract_transactions(pdf_path): print(pdf_path) rows = [] full_text = pdf_to_text(pdf_path) for page_text in full_text.split("\f"): page_start = len(rows) for line in page_text.split("\n"): if not line.strip(): continue if TRANSACTION_START.match(line): rows.append(parse_transaction(line)) continue if len(rows) <= page_start: continue indent = len(line) - len(line.lstrip(" ")) if indent < CONTINUATION_INDENT: continue parts = FIELD_SPLIT.split(line.strip()) rows[-1]["desc"] += " " + parts[0] if len(parts) > 1: rows[-1]["account"] = (rows[-1]["account"] + " " + parts[1]).strip() return rows def main(): pdf_dir = Path(sys.argv[1]) out_path = pdf_dir.with_suffix(".csv") all_rows = [] for pdf_path in sorted(pdf_dir.glob("*.pdf")): all_rows.extend(extract_transactions(pdf_path)) with open(out_path, "w", newline="") as f: writer = csv.DictWriter(f, fieldnames=["date", "desc", "account", "amount", "balance", "currency"]) writer.writeheader() writer.writerows(all_rows) print(f"Wrote {len(all_rows)} transactions to {out_path}") if __name__ == "__main__": main()