一本整本书丢进去,界面那个字符数到底数的是什么
把整本古书拖进文本读取页,信息栏一次给四栏:文件名、大小、行数、字符数。小样本上这几个数总凑在一起,整本进去才分岔。
这两部 TXT 都是从资源页存回来的整本公版古籍:唐诗三百首那份 81474 字节,九章算术那份 78497 字节,存下来就原样喂进文本读取页,中间不做任何切片。结论先摆这儿:界面那栏字符数数的是 UTF-16 码元,不是字节也不是码点;唐诗那部让码元比码点多了 1,九章那部一个都不多。至于四把尺各自的定义:字节是 Buffer 长度,码元是字符串 length,码点是 [...text].length,汉字按基本区正则数。
码元比码点多的那 1
唐诗码元 29218、码点 29217,界面显示前者。多出的 1 来自一枚扩展 F 区的字,码点 U+2CB3B、位于码点下标 7519,它在 UTF-16 里要占 2 个码元、只占 1 个码点,于是界面比人眼多 1。九章按代理对筛下来是 0 枚,码元与码点同为 27071。那枚字不在基本区正则的范围内,所以没被算进汉字 22123。这不是页面读错,是尺子的口径;两部真实大书把「码元 ≠ 码点」与「码元 = 码点」同时摆了出来。
图 1:每个量上条唐诗、下条九章;只有码元与码点这两格,唐诗的两个数字差 1,九章完全同数。
判定链停在第②步
两部首 3 字节实测都是 227,128,144,即「【」的 UTF-8 编码,不是 BOM,BOM 分支落空;接着 UTF-8 严格一次整篇解通,链子停在第②步返回 utf-8,GBK 严格与回落宽松那两步从不进入,所以编码栏显示「自动检测: UTF-8」。大小栏走 KB 档,各印 79.6 KB 与 76.7 KB。行数栏 2992 与 1305 含末尾空段:非空 2024 与 888,两部都没有 CR、末尾都带换行。最长行 529 码元在第 829 行、216 码元在第 534 行。
整篇按 GBK 误读的那笔账
本机造不出 GBK 字节,所以「真 GBK 文件被当成 UTF-8 解」那一向标未实测;能给的是反向:把 UTF-8 字节整篇交给 gbk 宽松解码。唐诗得 44212 码元、含 1915 枚 U+FFFD;九章得 41116 码元、含 736 枚。字符数那栏从 29218 跳到 44212。
段数却不为所动,仍 2992 与 1305——LF 在 GBK 下是合法单字节,不参与双字节配对。
先撞渲染上限,不是大小门槛
单本离 50000 段还差 47008(唐诗)与 48695(九章)。要撞线得靠拼接:16 部 47857 段不触发,17 部到 50848 段才触发尾行「... 文件过大,仅显示前 50000 行(共 50848 行)」;九章 38 部 49553 段不触发,39 部到 50857 段触发。同一时刻拼接体只有 1385058 与 3061383 字节,是大小门槛 10485760 的 13.21% 与 29.20%;单本低到 0.777% 与 0.749%——先撞的是渲染上限。
图 2:段数那一侧已经撞线,字节那一侧只走了 13.21% 与 29.20%。
书自己的名目账
尺子放回书本身。唐诗的篇题行 /^【[^】]*】$/ 数到 320 首,独立成行的卷目标题一个都没有(卷头正则命中 0),句号 1424 个。九章有 9 个卷头,题号 226 条,逐卷是方田 35、粟米 42、衰分 18、少广 22、商功 26、均输 26、盈不足 18、方程 17、句股 22,加回正好 226,句号 1166 个。这些章名在本篇只是文件里数出来的字符串,不展开。
搜索只认文件里真实存在的串
- 此版《静夜思》是「床前看月光」与「举头望山月」,各命中 1
- 通行本的「床前明月光」「举头望明月」在这份 81474 字节的文件里命中 0
- 九章「术曰」202、「答曰」253、「今有田广十五步」命中 1
- 「〔一〕」命中 9,因为九卷题号都从〔一〕重编;只留前缀「〔一」涨到 98
查询要先过一遍元字符转义再拼正则,那个转义类实际覆盖 14 枚 ASCII 元字符;命中数与肉眼 substring 计数逐例相等。
两套口径,和文案对照
以上都是纯 Node 字符串层的实测,界面层是另一套口径。字符串层能顺带核两条:escHtml 在这两部书上等于空操作,/&/g 与 /"/g 在两份全文都 0 命中,进 DOM 前不会有实体展开改变长度;行号等于切分下标加 1,1 到 2992、1 到 1305 逐位核对全部相等。真实浏览器里 2992 行的渲染、sticky 行号与滚动、高亮 span 的个数、复制到剪贴板的内容,一律标未实测——这一轮没开浏览器。
文案也按两部真实大书的读数判过:拿 config/tools.php 第 1497 行起这一页的 intro 与 summary,加上模板里那句拖拽文案「支持 UTF-8 / GBK / Big5 / Shift-JIS,最大 10MB」逐条对,8 条判定里 [一致] 6、[冲突] 0,两处部分一致。一处是「显示文件大小、行数、字符数」——字符数按码元给,唐诗 29218 不等于码点 29217;另一处是那句列了四种编码,自动检测只吐 utf-8 与 gbk 两个出口,Big5 与 Shift-JIS 要手动选,手动选就会在这两份 UTF-8 文件上产出一大片替换字符。
常见问题
Q:字符数比我数的字数多一个,是页面读错了吗?
那一栏数的是 UTF-16 码元。唐诗有 1 枚扩展 F 区的字(码点 U+2CB3B)占 2 个码元、只占 1 个码点,29218 就比码点 29217 多 1;九章 0 枚代理对,27071 在两个口径上相同。
Q:整本丢进去会被 10MB 那条拦住吗?
这两部不会,81474 与 78497 各占 10485760 的 0.777% 与 0.749%。真要先撞线,撞的是 50000 段渲染上限:拼到 17 部 50848 段或 39 部 50857 段才触发尾部提示,那时字节也只到 13.21% 与 29.20%。
Q:下拉切成 GBK,行数会跟着乱吗?
字符数会变,行数不变。唐诗按 GBK 误读得 44212 码元含 1915 枚替换字符、九章 41116 码元含 736 枚,段数仍是 2992 与 1305,因为 LF 在 GBK 下是合法单字节、不参与配对。