一本整本書丟進去,介面那個字元數到底數的是什麼
把整本古書拖進文本讀取頁,資訊列一次給四欄:檔名、大小、行數、字元數。小樣本上這幾個數總湊在一起,整本進去才分岔。
這兩部 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 下是合法單字節、不參與配對。