杂记 › 生活随笔 › 字帖每页放几个字:默认 A4 是 20 个,不是 100÷4=25

字帖每页放几个字:默认 A4 是 20 个,不是 100÷4=25

给一年级的孩子打一张字帖,状态栏写着「每页 10 行 · 每行 10 格」,那就是 100 个格子;一个「范字 + 描红 + 2 空格」要吃 4 格,100 ÷ 4 = 25,我敲了 25 个字,打印出来却是两张纸,第二页挂着 5 个字。默认的 A4 每页只有 20 个字,不是 100 ÷ 4 得到的 25 个——复现过装箱代码才明白,它用的从来不是这道除法。

每页字数 = floor(每行格数 ÷ 组宽) × 每页行数

711–734 行的装箱一组一组往当前行里塞,「再塞一组就超过每行格数」(717 行)就整组另起一行:组不跨行,行末余格作废。

默认版式(A4 纵向、格宽 16mm、边距 10mm、开拼音、每页信息栏)实测 cols=10、rowsPerPage=10,mtb 的组宽是 4,floor(10 ÷ 4) × 10 = 20,每行 2 组、余 2 格;差的 5 组正是每行 2 格 × 10 行 = 20 个排不进内容的格子位。儿童练字字帖生成 的说明区写的就是这道除法。

换 pattern 就是换组宽

格宽 12mm 配「窄」边距 6mm 把每行顶到 14 格、每页顶到 13 行,A5 同参数只剩 7 格 7 行;这五组在 Node 与 headless Chrome 上各跑一遍完全一致。

版式每行格数每页行数每行组数 / 余格每页字数
A4 默认 mtb10102 组 / 余 220
A4 默认 mb10103 组 / 余 130
A4 默认 m(整行范字)101010 组 / 余 0100
A4 格宽 12mm + 边距 6mm14133 组 / 余 239
A5 默认参数 mtb771 组 / 余 37

关拼音只动行数

拼音那一横带高 = 格宽 × 0.4,16mm 即 6.4mm(662、671–672 行):关掉它每页 13 行、26 个字,信息栏改「不显示」是 11 行、22 个字,两个都关 14 行、28 个字。状态栏(1067–1069 行)原文「每页 10 行 · 每行 10 格 · 格宽 16 mm · 练习位 44」,不说每页几个字。

三条上限各管一件事

600 数的是非空白字符(742–744 行):600 个字夹空格时原始长度已达 1,199 仍不截,640 个字(raw 1,279)才触发「内容超过 600 个字,已截断。」(1075 行)。

40 页是一笔行预算,maxRows = rowsPerPage × 40(759–761 行):默认版式预算 400 行,600 个字只排到 300 行,「已达到 40 页上限」在默认版式永远打不出来。

组宽大于每行格数是第三条路:A5 + 格宽 30mm + 宽边距 15mm → cols=3、rows=3,716 行的 slice(0, cols) 把组尾 1 个空格砍了,11 个字排 11 行 4 页;提示前半句是「每行只放得下 3 格,装不下「 4 格一组」,超出的空格已丢弃。」

让 40 页那条提示可达

A5 + 格宽 20mm + mtb:rowsPerPage 5、maxRows 200。201 个字开始提示并丢 1 个,600 个字被 slice 到 200 行、一次丢 400 个,而 pageCount 仍是 40,被丢掉的行不在预览里。

0 0 1 50 400 199 字 200 字 201 字 250 字 600 字 被丢掉的字数 行预算 200

图 1:输入长度对着行预算 200 的丢字量。

#py: 那一格认什么、不认什么

页面提示(73 行)让另起一行写 #py: yin1 yue4,落不落得进格子取决于 586 行的守卫 /^[a-z]+[0-9]$/:

  • 纯 ASCII 音节加数字声调才转:tian1 → tiān、lve4 → lüè;
  • 带调字母原样用,全角冒号 #py:、#PY: 和带序号的写法都认;
  • 混写不转,数字留在格子里印出来:lüe4、yuè4、TIAN1。

直调 applyToneMarks 传 lüe4 只剩 è(377 行的正则不收 ü),但 586 行把它挡在界面外,页面上只是残留数字。

拼音表 2,639 个键,44 个重复

Object.keys(PINYIN_MAP).length 是 2,639:303–350 行字面写了 2,676 条、44 个键重复(去重剩 2,632),353–359 行补录 7 个漏掉的高频字(粒 得 区 我 为 而 西)。后写盖先写,9 个取值相同没有副作用,35 个两读不同的留下常常不是常用音——了 → liǎo(le0 写在 325 行前面)、阿 → ē、省 → xǐng。核对读音可先用 汉字转拼音 转一遍,两边是同一份表。

空格不分组,标点和数字都占格

汉字模式下 567–578 行把空白全部丢弃,天 地、天地、换行、制表符四种输入等价——「不占格子」对,「用来分组」不成立。只有拼音和数字那条分支按空白分组(605–614 行,609 行连制表符都不算):ni hao 是 2 个 unit、nihao 是 1 个。快捷字表「词语练习」那串 朋友 同学 … 因此排成 21 个连排单字。

标点和数字一格一个:123 456 是 6 个 unit,「静夜思」的 , 。 也各占一格。没收录的不猜:魃鑫龘弼黉 5 个字留空并计入 miss 提示(1081 行),^丨丶 这类字符也计 miss(实测 2)。

整行范字后面的空格不另起行

mrow 的 hint 说空格数就是空临行数,但 696–709 行是把 b 份「与内容等长的空格串」接在范字流尾巴上再连续装箱。默认 10 列下 11 字配空格数 1,行内是 MMMMMMMMMM / M········· / ··(空格数 8 时总格数 99 = 11×9)。

导出体积与 PDF 里装了什么

A4 单页 11 个字实测:JPEG 514,478 B、PNG 950,158 B(1.85 倍)、工具自写的 PDF 515,288 B,容器 810 B。PDF 每页是一张位图:内容流只有 36 字符的 q … cm /ImN Do Q、没有文字操作符(1450、1454 行)。导出按 12 px/mm=305dpi,直接打印是 8 px/mm≈203dpi,超过 15 页降到 6 px/mm≈152dpi(470–472、1255 行)。

把页面文案逐条对回代码

config/tools.php 里 2205–2209 行那段说明对着当前模板复现,是 33 条 = 28 条 [一致] / 5 条 [冲突]:写死的 2639、每页 20 / 30 / 100 / 39、关拼音 13 行、A5 的 7×7×1、305 / 203 / 152dpi 全部命中;剩下 5 条都是口径级,把「按空白分组」「常用音」「都认」「40 页」「空临行数」说得太满。拼音数据的另一面见站内那篇 汉字加拼音注音。

三个容易踩的坑

Q1:把格距调到 0 多出一列,能多放一组吗?

不能。实测格距 0 时 cols 变 11,11 ÷ 4 仍取 2,每页还是 20 个字。

Q2:600 个字是从哪一段开始被丢的?

提示只说「已截断」(1075 行),不报起始位置,被丢的行也不在预览里。

Q3:不心算能不能知道一页放几个字?

页面上给不出,只能导一版数末页:默认每页 20 个字,25 个字就分两页;排长文换 mb(每页 30 个字)。

📎 相关文章

同一天既是周末又被登记成补班,工作日计算器听谁的 2026-10-27 倒计时里的 86400 秒一天,碰上夏令时会少给你 1 天 2026-10-27 世界时间的偏移是谁给的:一条正则,和一个没有夏令时的写死小时数 2026-10-27 同一次计算给出两个体脂率:默认一组差 6.1 个百分点,腰围 1 cm 值 0.7 2026-10-26 照片转了 90°,换台设备方向又回来了:EXIF 与真实旋转的分工 2026-10-22