SPB Git

spb/firc0001_uqo

Public
5.1 KB · 95 lines python
1import sys, re, datetime2from docx import Document3from docx.shared import Pt4from docx.enum.text import WD_ALIGN_PARAGRAPH5path = sys.argv[1]; doc = Document(path)6paras = doc.paragraphs7norm = lambda p: re.sub(r"\s+", " ", p.text.replace(" ", " ")).strip()8title = "From Corporate Disclosures to a Russell 3000 Strategic Project Database"9# --- title page: everything before the Abstract block is centred10i_abs = next(i for i, p in enumerate(paras) if norm(p) == "Abstract")11for p in paras[:i_abs - 1]:12    p.alignment = WD_ALIGN_PARAGRAPH.CENTER13    if norm(p) == title:14        for r in p.runs: r.font.size = Pt(18); r.font.bold = True15    elif norm(p).startswith("Identification, Measurement"):16        for r in p.runs: r.font.size = Pt(13)17# --- move References (pandoc appends it at the end) before the appendix, as in the PDF18h1 = [p for p in paras if p.style.name == "Heading 1"]19refs = next(p for p in h1 if norm(p) == "References")20appA = next(p for p in h1 if re.match(r"^A [A-Z]", norm(p)))21body = doc.element.body; kids = list(body)22i_refs, i_app = kids.index(refs._p), kids.index(appA._p)23moved = [k for k in kids[i_refs:] if k.tag.endswith("}sectPr") is False]24for k in moved: appA._p.addprevious(k)25# --- page breaks where the LaTeX source has \newpage26breaks = 027paras[i_abs - 1].paragraph_format.page_break_before = True; breaks += 128for p in h1:29    t = norm(p)30    if t.startswith("1 Introduction") or t == "References" or p is appA:31        p.paragraph_format.page_break_before = True; breaks += 132# --- document properties33cp = doc.core_properties34cp.title = title35cp.subject = "Identification, Measurement, Validation, and Research Applications"36cp.author = "Manel Kammoun; Djerrycharli Tandjambianda; Simon-Pierre Boucher"37cp.keywords = "SEC filings, text as data, corporate investment, strategic projects, information extraction, large language models, entity resolution, Russell 3000"38cp.comments = "UQO Working Paper No. 0001 (FIRC-funded), Version 1.0, October 28, 2026 (working draft under validation)"39cp.created = cp.modified = datetime.datetime(2026, 10, 28, 12, 0)40# --- base fonts closer to the PDF (Times)41from docx.oxml.ns import qn42for st in doc.styles:43    try:44        if st.type == 1 and st.font is not None and (st.name == "Normal" or st.name.startswith("Heading") or st.name in ("Title", "Body Text", "First Paragraph", "Compact", "Caption", "Bibliography", "Block Text")):45            st.font.name = "Times New Roman"46            rpr = st.element.get_or_add_rPr(); rf = rpr.find(qn("w:rFonts"))47            if rf is None:48                rf = rpr.makeelement(qn("w:rFonts"), {}); rpr.append(rf)49            for a in ("w:ascii", "w:hAnsi", "w:eastAsia", "w:cs"): rf.set(qn(a), "Times New Roman")50            if st.name in ("Normal", "Body Text", "First Paragraph", "Compact"): st.font.size = Pt(12)51    except Exception:52        pass53# --- wide tables: smaller font and tight cell padding so that 8-10 column tables fit the page width54from docx.shared import Inches55from docx.oxml import OxmlElement56for sec in doc.sections:57    sec.left_margin = sec.right_margin = Inches(0.85)58for tbl in doc.tables:59    ncol = max(len(r.cells) for r in tbl.rows)60    if ncol >= 7:61        size = Pt(7) if ncol >= 9 else Pt(8)62        tbl.autofit = True63        for row in tbl.rows:64            for cell in row.cells:65                for para in cell.paragraphs:66                    para.paragraph_format.space_after = Pt(0); para.paragraph_format.space_before = Pt(0)67                    for run in para.runs: run.font.size = size68                tcPr = cell._tc.get_or_add_tcPr(); mar = OxmlElement("w:tcMar")69                for side in ("left", "right"):70                    el = OxmlElement(f"w:{side}"); el.set(qn("w:w"), "30"); el.set(qn("w:type"), "dxa"); mar.append(el)71                tcPr.append(mar)72# --- proportional column widths for wide tables (pandoc emits equal 0.55-inch grid columns)73TOTAL = 9792  # twips: 8.5in - 2 x 0.85in margins74for tbl in doc.tables:75    ncol = max(len(r.cells) for r in tbl.rows)76    if ncol < 7: continue77    lens = [1] * ncol78    for row in tbl.rows:79        for j, cell in enumerate(row.cells[:ncol]):80            lens[j] = max(lens[j], min(28, max((len(w) for w in cell.text.split()), default=1)))81    weights = [max(l, 4) for l in lens]; tot = sum(weights); widths = [int(TOTAL * wgt / tot) for wgt in weights]82    grid = tbl._tbl.find(qn("w:tblGrid"))83    if grid is not None:84        for g, wd in zip(grid.findall(qn("w:gridCol")), widths): g.set(qn("w:w"), str(wd))85    tblPr = tbl._tbl.tblPr86    for e in tblPr.findall(qn("w:tblW")): e.set(qn("w:type"), "dxa"); e.set(qn("w:w"), str(TOTAL))87    for e in tblPr.findall(qn("w:tblLayout")): e.set(qn("w:type"), "fixed")88    for row in tbl.rows:89        for j, cell in enumerate(row.cells[:ncol]):90            tcPr = cell._tc.get_or_add_tcPr(); tcW = tcPr.find(qn("w:tcW"))91            if tcW is None: tcW = OxmlElement("w:tcW"); tcPr.insert(0, tcW)92            tcW.set(qn("w:type"), "dxa"); tcW.set(qn("w:w"), str(widths[j]))93doc.save(path)94print(f"post-processed: {i_abs-1} title-page paragraphs centred, {len(moved)} reference paragraphs moved before appendix, {breaks} page breaks, properties set")95
Files · e80ef398ede4f5784e4d15d7b4453d5f38c765cc
Menu

Theme