#!/usr/bin/env python3 """Merge manuscript/references.bib (main, Agent B-lit) with the writers' references_part*.bib into references_all.bib. First occurrence wins (main bib first); duplicate keys are reported in references_merge_report.txt with a flag when the DOI differs (a real conflict to resolve by hand). main.tex uses \\bibliography{references_all}.""" import glob, re, os H = os.path.dirname(os.path.abspath(__file__)) files = [os.path.join(H, "references.bib")] + sorted(glob.glob(os.path.join(H, "references_part*.bib")) + sorted(glob.glob(os.path.join(H, "references_app*.bib")))) seen = {}; out = []; dups = [] for f in files: txt = open(f, encoding="utf-8").read() for m in re.finditer(r"@(\w+)\s*\{\s*([^,\s]+)\s*,", txt): start = m.start(); depth = 0; i = m.end() - 1 # find matching closing brace of the entry j = txt.find("{", start); depth = 0; k = j while k < len(txt): if txt[k] == "{": depth += 1 elif txt[k] == "}": depth -= 1 if depth == 0: break k += 1 entry = txt[start:k + 1]; key = m.group(2) doi = re.search(r"doi\s*=\s*[{\"]([^}\"]+)", entry, re.I) doi = doi.group(1).strip().lower() if doi else None if key in seen: dups.append((key, os.path.basename(f), "DOI_CONFLICT" if (doi and seen[key] and doi != seen[key]) else "same")) continue # verification notes live in the CSVs; strip them from the printed bibliography (aer.bst prints `note`) entry = re.sub(r",\s*note\s*=\s*[{\"]verified[^}\"]*[}\"]", "", entry) seen[key] = doi; out.append(entry) open(os.path.join(H, "references_all.bib"), "w", encoding="utf-8").write("% merged by merge_bibs.py — do not edit; edit the source bib files\n\n" + "\n\n".join(out) + "\n") with open(os.path.join(H, "references_merge_report.txt"), "w") as fh: fh.write(f"entries: {len(out)} from {len(files)} files\n"); [fh.write(f"DUP {k} in {f}: {st}\n") for k, f, st in dups] print(len(out), "entries;", len(dups), "duplicates;", sum(1 for d in dups if d[2] == "DOI_CONFLICT"), "DOI conflicts")