import FS from 'fs'; import path from 'path'; import JSZip from 'jszip'; const file = path.join( 'C:/Users/Administrator/Desktop/IN2026A0418001_final_20260713 1.docx' ); const buf = FS.readFileSync(file); const zip = await JSZip.loadAsync(buf); const xml = await zip.file('word/document.xml').async('string'); const drawings = (xml.match(/ b[1] - a[1]) .slice(0, 20) ); // Extract paragraphs containing "Figure" with nearby text const paras = xml.split(/<\/w:p>/); let figParaCount = 0; for (let i = 0; i < paras.length; i++) { const p = paras[i]; const texts = [...p.matchAll(/]*)?>([\s\S]*?)<\/w:t>/g)].map((x) => x[1]); const plain = texts.join('').replace(/&/g, '&').trim(); if (!/^Figure\s+\d+/i.test(plain) && !/^Fig\.?\s*\d+/i.test(plain)) continue; figParaCount += 1; const hasDrawing = / x[1]); // next non-empty para let nextPlain = ''; for (let j = i + 1; j < Math.min(i + 5, paras.length); j++) { const nt = [...paras[j].matchAll(/]*)?>([\s\S]*?)<\/w:t>/g)] .map((x) => x[1]) .join('') .replace(/&/g, '&') .trim(); if (nt) { nextPlain = nt.slice(0, 220); break; } } // prev: look back for drawing-only paragraphs let prevHasDrawing = false; for (let j = i - 1; j >= Math.max(0, i - 6); j--) { if (/]*)?>([\s\S]*?)<\/w:t>/g)] .map((x) => x[1]) .join('') .trim(); if (pt && !/^[AB]$/.test(pt)) break; } console.log('---'); console.log('caption:', plain.slice(0, 160)); console.log('colors:', [...new Set(colorVals)]); console.log('sameParaDrawing:', hasDrawing, 'prevHasDrawing:', prevHasDrawing); console.log('next:', nextPlain); } console.log('figParaCount', figParaCount); // Check standalone A/B label paragraphs near figures let abCount = 0; for (const p of paras) { const plain = [...p.matchAll(/]*)?>([\s\S]*?)<\/w:t>/g)] .map((x) => x[1]) .join('') .trim(); if (/^[AB]$/.test(plain)) abCount += 1; } console.log('standalone A/B paras', abCount);