Docx placeholder replacement
[COLM'26] SkillLearnBench is the first benchmark for evaluating continual learning methods that automatically generate agent skills.
npx -y skills add cxcscmu/SkillLearnBench --skill docx-placeholder-replacementAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Robustly replace {{PLACEHOLDER}} tokens in Word documents, handling split runs across paragraphs, tables, headers, and footers.
SKILL.md
2.4 KB, as published. Nobody here has run it
Robust Placeholder Replacement in Word Documents
The Split-Run Problem
Word's XML engine often breaks a single word like {{CANDIDATE_NAME}} across multiple runs:
run[0]: '{{CANDI'
run[1]: 'DATE_NAME}}'
A naive run.text.replace() will miss these. Always reconstruct from para.text.
Safe Replacement Algorithm
import re
def replace_in_paragraph(para, data):
"""Replace all {{KEY}} placeholders in paragraph, handling split runs."""
full_text = para.text
pattern = re.compile(r'\{\{([A-Z0-9_]+)\}\}')
if not pattern.search(full_text):
return # Nothing to do
# Build replacement
def replacer(m):
key = m.group(1)
return str(data[key]) if key in data else m.group(0)
new_text = pattern.sub(replacer, full_text)
if new_text != full_text and para.runs:
# Put all text in first run, clear the rest
para.runs[0].text = new_text
for run in para.runs[1:]:
run.text = ''
Apply to Entire Document
def replace_all_placeholders(doc, data):
"""Replace placeholders everywhere: body, tables, headers, footers."""
# Body paragraphs
for para in doc.paragraphs:
replace_in_paragraph(para, data)
# Tables (with nested table recursion)
def process_table(table):
for row in table.rows:
for cell in row.cells:
for para in cell.paragraphs:
replace_in_paragraph(para, data)
for nested in cell.tables:
process_table(nested)
for table in doc.tables:
process_table(table)
# Headers and footers
for section in doc.sections:
for para in section.header.paragraphs:
replace_in_paragraph(para, data)
for para in section.footer.paragraphs:
replace_in_paragraph(para, data)
Notes
- Only the first run's formatting is preserved after merging. If parts of the placeholder text have different formatting (e.g., bold
{{NAME}}), that formatting is lost — which is usually acceptable for template filling. - Unknown placeholders (keys not in
data) are left as-is by default. Adjust thereplacerfunction to raise errors or substitute empty strings if needed.