雜記 › 技術筆記 › 文字分列後空欄位沒丟:a,,b 照留、列號越界填空、填 0 或 abc 退回全部列實測

文字分列後空欄位沒丟:a,,b 照留、列號越界填空、填 0 或 abc 退回全部列實測

把 text-column 的腳本原文在沙箱裡逐字跑,實測分列與合併兩檔:Tab 檔那個 value 是 2 字元字面量、空欄位全部保留、列號越界填空而填 0 退回全部列,兩套行過濾口徑各記各的帳。

空欄位沒丟,是我一開始想錯了

先說結論:貼進分列框的 a,,b,兩個逗號中間那個空欄位沒被吃掉;「保留列號」填 2 得到 0 位元組的行、填 0 反而三列全吐出來。三個分支同出一條鏈。

受測頁是 文字分列與合併:模板 10134 位元組,<script> 原文 4123 字元 / 94 行。頁面共三檔 tab,本篇只測前兩檔,第三檔見舊文笛卡兒積。讀數出自 Node 沙箱加 DOM stub,真機只讀回靜態屬性;CRLF 是否正規化、點 tab 後各框初值、rows 與捲動、大於 1 MB 輸入的卡頓,四項未實測。

Tab 檔的 value 是 2 個字元

L26 與 L41 那兩個 tab 選項都寫 value="\t",是反斜線加小寫 t 共 2 字元;真機讀回是 U+005C U+0074,與 String.fromCharCode(9) 判不相等。getSep 只認這 2 字串、換成 U+0009,另外 10 個入參全部原樣返回。資料裡是字面量 \t 時(a\tb\tc 共 7 字元),選 Tab 檔切不開、輸出原樣 7 位元組。

空欄位一律保留

doSplit 的 else 分支只 map 加 join、不 filter,相鄰兩個分隔符之間必產出一個空字串,它原樣活到輸出(輸入輸出同取逗號檔):a,,b 切 3 段、輸出 4 位元組,行尾 a,b, 留 4 位元組帶一個空尾段;輸出換 - 檔時 a,,b 出 8 位元組的 a - - b。段數帳是「分隔符數 + 1」,首屏每行 2 個逗號對 3 段。空欄位這種空只由相鄰分隔符生成:只選它(列號 2)得 0 位元組的行,統計條卻報輸出行數 1。

保留列號:1 基、照給定順序、不去重

鏈是整格 trim、按逗號 split、每片 parseInt(s.trim(), 10)、濾掉 NaN 與非正數,取值用 parts[idx - 1] 所以是 1 基,選空了才走全列。基準行 张三,25,北京,輸出分隔符臨時換直線:

列號填實測輸出讀法
1,3张三|北京5 字元
1,5张三|越界填空
50 位元組的行不丟行,報 1
2,,325|北京空片被濾
1 - 3、1<TAB>2张三截成 1
0、abc、全形2张三|25|北京退全列

越界這種空來自 5 打在 3 段的行上:填空字串、不丟行、統計報 1。非法這種空來自 0、abc、全形2:整格作廢退全列,跟留空同一條分支。

邊角都出自 parseInt:1.9 讀成 1、2.99 讀成 2、 007 讀成 7。量級再大輪到浮點:21 位的 999999999999999999999 讀回 1e+21,那個 idx - 1 在這量級不改變值,取到的仍是 undefined、輸出 0 位元組而統計報 1。

兩套行過濾:一個看長度,一個 trim 後看

分列用 filter(l => l.length > 0):a,b、空格行、c,d、真空行、d,e 共 5 段,報輸入行數 4、輸出 12 位元組 4 行,空格行是 0 位元組空行——行數算它、內容看不見它,改選列 1,2 才讓它現形,成 , 1 位元組。CRLF 的空行是 1 個 \r、長度為 1,過得了這條判定(3 對 2)。合併檔帶 trim,空白行不進帳:B 側塞 1 個空格行加 1 個真空行仍報列表B 3、輸出仍 27 位元組;A 側掉 1 行就整排錯位,末行成 - z。

只含空白的行,兩檔各記什麼帳 分列 length > 0:空格行活,5 段報 4 行 CRLF 空行是 1 個回車 帶它算 3 行,LF-only 算 2 合併 trim 後判長度:不進帳

圖 1:同一條看不見的行,兩檔各記各的帳

doMerge 取兩側較大者,缺側照掛連接符

A 給 5 行、B 給 3 行、連接符用預設 - :結果 5 行 27 位元組,前 3 行 a - x 各 5 位元組,末兩行是 d - 這種 4 位元組——缺的那側填空字串,不減行,尾巴掛著連接符;B 長則頭掛 - d。連接符填空字串才有乾淨的 d,5 行 12 位元組;兩側都空才 0 行、統計報 0/0/0。50 行配 37 行出 442 位元組,比空連接符檔的 292 多 150,正是 50 行乘 3 位元組連接符,缺側 13 行照拼。

冪等只在空行處破

同取逗號檔時:乾淨資料三趟逐位元組相等、都是 33 位元組;帶內邊空格的 张三, 25 ,北京 第一趟把 18 位元組改成 16 位元組,之後穩定在 16。破口是空格行——樣本 P(53 段 / 580 位元組,含 1 空格行)連跑四趟是 580、578、577、577,空格行在第一趟被寫成空行、第二趟才濾掉,行數從此永久少 1(52 行變 51 行)。

空格檔對空欄位可逆(a,,b 變兩個連空格、8 位元組不動),對欄位內空格不可逆(New York,25 切回來 2 段變 3 段、26 位元組不變)。 - 檔是單向門:张三,25 出 7 字元 / 11 位元組,而真機讀回輸入分隔符 5 檔的 value 裡沒有它,同頁切不回來。

批次樣本 M 與參差樣本

M 是 50 行混合加 1 空格行加 1 真空行加 1 行 row33,a,,b,共 53 段 / 775 位元組;五檔都是 52 行輸出,空格行仍留在輸出裡。逗號檔 703 位元組 / 663 字元; - 檔 909 位元組,最寬 26;只保留 3 檔 136 位元組裡有 22 行是 0 位元組空行。全形逗號不入檔,r3,v3,w3,x3 只切 1 刀。

寬窄帳不屬於 M:參差樣本(三列列數不齊)四個單字元輸出檔同寬 29 字元 / 49 位元組,換 - 檔是 41 字元 / 61 位元組,差的 12 位元組 = 分隔符總數 6 乘 2——列數不齊,不是內容長短不齊。

它不認引號,也沒有失敗路徑

帶引號的欄位 a,"b,c",d 是 9 字元,逗號檔切出 4 段,被引號包住的那段劈成兩半。所以「從 CSV 資料中提取指定列」那句在文案對照裡判 [衝突]。這一頁沒有報錯路徑:maxlength、alert(、try {、onerror 各命中 0 次,非法輸入只有靜默兜底——整份 trim 後為空就清空輸出框與統計條。

三本位元組帳別串用

首屏三行樣例共 26 字元,走預設雙逗號檔輸出 50 位元組且與輸入逐位元組相等;49 與 61 位元組屬於參差樣本那兩檔;703 與 909 位元組屬於批次樣本 M 的 52 行。容量與顯示無關:rows=6 只是顯示行數,91669 位元組的 5000 行樣本單趟 3.52 至 3.93 ms、單行 5000 段不足 1 ms,都是沙箱純計算耗時、不含 DOM 寫入與 paint。行級加前後綴或編號是另一檔工具的活,舊文加前綴與序號寫過。

Q:a,,b 中間那個空欄位還在,是沒切乾淨?

切乾淨了:2 個逗號對 3 段,中間那段本來就是空字串,不濾空段,join 回去仍是 4 位元組;要它消失只能讓列號跳過第 2 列。

Q:保留列號填了 0,為什麼三列全出來了?

0 被「非正數就濾掉」那條濾掉,abc 同理,整格一個不剩,就跟留空一樣走全列分支。

Q:貼進表格軟體每行多出一列空的,怪哪一步?

兩種輸入不同:行尾多打的分隔符,a,b, 帶一個空尾段;合併缺側的 d - ,末尾還掛著連接符。

📎 相關文章

120 個詞槽、15 條整句、1 句寫死的開頭:lorem-ipsum 的詞表清點與重複片段實測 2026-11-05 SVG 預覽的尺寸到底聽誰的:顯示框恆等於容器,刪掉 viewBox 之後 r=1 實測 2 像素 2026-11-05 13 位連寫只截出 11 位:text-extract 七個內建型別的正則邊界實測 2026-11-05 1 GB 文件由 1024 塊拼成:任意大小文件生成的分塊節奏、取消邊界與三種填充位元組 2026-11-04 文件名提取的三處邊界:結尾斜槓只兜一格、查詢串整塊留下、空行靜默消失 2026-11-04