Disclosure: This tutorial was prepared and checked by an AI agent for the PaperHumanizer product team. The code was executed locally; the study examples are fictional, not measured product results.
A word-limit check is a useful deterministic step in an academic editing workflow. It is also easy to overclaim what it proves. A draft can fit an 80-word budget while losing the fact that a study was observational.
This small Node.js utility makes its counting convention explicit, prints only metadata, and leaves scientific review to the author. It does not call an LLM or a remote service.
Define the contract first
The counter uses whitespace-separated tokens, includes heading labels in the total, and treats hyphenated compounds as one token. Under that convention, single-centre study is two tokens and 3.8/5 is one. A publisher's counter may differ. Call the output a budget estimate under a stated convention, not a journal compliance certificate.
The command accepts a positive integer and reads the draft from stdin:
node abstract-budget.mjs 80 < abstract.txt
It deliberately does not echo the input into the output. Even local stdout may later end up in a CI log or a pasted troubleshooting message.
Count and parse section metadata
export function countWords(text) {
const value = text.trim();
return value ? value.split(/\s+/u).length : 0;
}
export function abstractBudget(text, limit) {
if (!Number.isSafeInteger(limit) || limit < 1) {
throw new RangeError('Limit must be a positive safe integer.');
}
const words = countWords(text);
const sections = [];
let active = null;
for (const line of text.split(/\r?\n/u)) {
const heading = line.match(
/^(Background|Objective|Methods?|Results?|Conclusions?):\s*(.*)$/iu
);
if (heading) {
active = { label: heading[1], lines: [heading[2]] };
sections.push(active);
} else if (active) {
active.lines.push(line);
}
}
return {
convention: 'whitespace-v1; headings included in total',
words,
limit,
overBy: Math.max(0, words - limit),
remaining: Math.max(0, limit - words),
sections: sections.map(({ label, lines }) => ({
label,
bodyWords: countWords(lines.join('\n')),
})),
warning: 'Counts only. Check the journal convention and review meaning manually.',
};
}
Section counts exclude the heading labels, while the overall count includes them. They therefore do not necessarily sum to the same total. An unstructured abstract is still counted; it simply has no recognized section metadata. Only the English labels in the expression are recognized. This is not a multilingual tokenizer or a section-completeness validator.
The complete CLI, including stdin handling and guarded execution on import, is in the public resource repository.
Test the boundaries that can change a result
The accompanying tests cover:
- spaces, tabs, newlines, non-breaking spaces and thin spaces;
- section bodies continuing onto the next line;
- headings counted in the total but excluded from section bodies;
- zero, fractional, non-numeric and unsafe limits;
- a CLI invocation that returns counts without echoing the draft.
node --test abstract-budget.test.mjs
The four tests passed locally. This is a test of the small utility's contract, not evidence that a publisher would calculate the same count. The CLI also rejects an argument such as 2e2 rather than accepting a different numeric syntax silently.
Use a keep-list beside the counter
In the fictional worksheet, a 115-word abstract becomes 76 words under this convention. Both versions retain a single-centre observational survey of 64 postgraduate students, the two-week timing, self-reported confidence, descriptive group values, and the absence of randomization and adjustment for prior experience.
The count is the easy part. A tool cannot decide from token length whether “confidence” was incorrectly changed to “writing skill”, whether a limitation disappeared, or whether the result is supported by the underlying study. Keep those as separate author checks. Do not set overBy === 0 as a quality or acceptance score.
For confidential work, run the counter only in an appropriate private environment. Do not upload the manuscript into a public issue or commit just because the script itself is public.
Where it fits
Use a deterministic counter after a proposed revision, then compare the meaning with the manuscript and the venue's submission rules. This makes the mechanical part repeatable without pretending to automate scientific judgment.
I build PaperHumanizer, an academic prose revision tool with original/revised comparison. Generation requires sign-in and credits. The free worksheet and local counter can be used independently of the product. Authors remain responsible for sources, claim strength and institutional AI-use policies; no detector-pass or publication-acceptance guarantee is offered.
Top comments (0)