83 lines
2.5 KiB
JavaScript
83 lines
2.5 KiB
JavaScript
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(/<w:drawing/g) || []).length;
|
|
const blips = (xml.match(/a:blip/g) || []).length;
|
|
console.log('drawings', drawings, 'blips', blips);
|
|
|
|
const colors = {};
|
|
for (const m of xml.matchAll(/w:color\s+w:val="([^"]+)"/g)) {
|
|
colors[m[1]] = (colors[m[1]] || 0) + 1;
|
|
}
|
|
console.log(
|
|
'colors top',
|
|
Object.entries(colors)
|
|
.sort((a, b) => 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(/<w:t(?:\s[^>]*)?>([\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 = /<w:drawing/.test(p);
|
|
const colorVals = [...p.matchAll(/w:color\s+w:val="([^"]+)"/g)].map((x) => 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(/<w:t(?:\s[^>]*)?>([\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 (/<w:drawing/.test(paras[j])) {
|
|
prevHasDrawing = true;
|
|
break;
|
|
}
|
|
const pt = [...paras[j].matchAll(/<w:t(?:\s[^>]*)?>([\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(/<w:t(?:\s[^>]*)?>([\s\S]*?)<\/w:t>/g)]
|
|
.map((x) => x[1])
|
|
.join('')
|
|
.trim();
|
|
if (/^[AB]$/.test(plain)) abCount += 1;
|
|
}
|
|
console.log('standalone A/B paras', abCount);
|