杂记 › 技术笔记 › 文件名提取的三处边界:结尾斜杠只兜一格、查询串整块留下、空行静默消失

文件名提取的三处边界:结尾斜杠只兜一格、查询串整块留下、空行静默消失

备份日志贴进去提取,20 行只出 16 行:3 行空白不计、那行单独斜杠被静默吞掉。结尾分隔符的回退只兜一格,查询串整块留在名字里,取消扩展名的那一刀还看小数点——统计条 17、16、14 每一格都有账可对。

先把行数差额算清楚

把一份备份日志整贴进输入框,每行一个路径,点提取,输出比输入少了几行——先别急着怀疑工具漏行。我拿 20 行夹具对账,统计条显示 总路径数:17、提取文件名:16、唯一文件名:14:3 行空白在计数前就被跳过,连 17 都没进;那行单独的斜杠进了 17,却在输出里被无声丢掉,停在 16。输出与输入不再按行号对应,界面不会说是哪一行。

结尾分隔符的回退:只兜一格

D:\a\ 切分得 3 段,末段空,回退一格拿倒数第二段,交出 a;/var/www/ 与 a/ 同理。但回退没有循环:末尾连写两个分隔符的 D:\a\\ 末段与次末段全空,返回空串;a//、单独一行的 / 与 \ 同样。中段连续反而无害,取末段不看空段,a//b.txt 照出 b.txt。

回退只查倒数第二段一次,没有循环(左列为输入原串)输入与切分返回"D:\a\" → 3 段 ["D:","a",""]出 "a""D:\a\\" → 4 段 ["D:","a","",""]出 "",整行被丢"a//" → 3 段 ["a","",""]出 "",被丢"/" 与 "\" → 2 段 ["",""]出 "",被丢"C:\" → 2 段 ["C:",""]出 "C:"(2 字符)"/report.pdf/" → ["","report.pdf",""]出 "report.pdf"(10 字符)

图 1|兜一格与兜不住的区别,全在同一函数里逐字实测。

两种分隔符的入门判断见上一篇从路径里批量提取文件名;这里只量不报错的位置。

统计条三个数与开关四组合

行数账:20 行里 3 行 trim 后为空、不进 total,1 行抽出空名被丢,16 减 14 等于 2——report.pdf 与 photo.JPG 各重复两次。字节账:

开关组合统计条(总数/提取/唯一)输出
扩展名勾上、不去重17 / 16 / 1416 行,165 字节
扩展名勾上、去重勾上17 / 14 / 1414 行,144 字节
扩展名取消、不去重17 / 16 / 1416 行,102 字节
扩展名取消、去重也勾上17 / 14 / 1414 行,89 字节

输出只用 LF 拼接、结尾不带换行。CRLF 与 LF 两版夹具的统计三数与输出字符数完全一致(17、16、165),差的只是输入字节(374 对 355);结尾多粘一个换行把切分从 20 段推到 21 段,统计条纹丝不动。

输出字节条与行数(统计条三数见上表)扩展名勾上、不去重165 B / 16 行扩展名勾上、去重勾上144 B / 14 行扩展名取消、不去重102 B / 16 行扩展名取消、去重也勾上89 B / 14 行

图 2|同一夹具四种开关的输出字节(条长按每字节 2 单位)。

查询串与片段:整块留在名字里

一条 50 字符的 CDN 地址,勾选扩展名输出 22 字符的 a.jpg?w=800&h=600#frag:本页拿行只按分隔符切段,?query#frag 就是名字的一部分,不解析 URL,也不还原百分号编码。

取消扩展名后画风突变。这 22 字符里只剩「a.jpg」前那一个点,位于 index 1,一刀削掉 21 个字符,94.5% 蒸发,只剩 1 个字符的 a。点更多的有曲折:/files/report.csv?v=1.2 取消扩展名得 14 字符的 report.csv?v=1,最后一个点落在查询值 1.2 的小数点上,削剩的串带着 ?v=,既不是文件名也不是干净的扩展名切分;/download/report.pdf?v=2 反而干净,输出 report。URL 和 Windows 路径走的是同一把刀。

点号刀法:规则两条,变形全从规则来

「取消包含扩展名」的实现只有两句:在末段找最后一个点,位置严格大于 0 才下刀。逐条实测:

  • 多段扩展名只削最后一段:a.tar.gz 变 a.tar(5 字符)、archive.tar.bz2 变 archive.tar(11 字符)、a.b.c.d 变 a.b.c;
  • 点在第 0 位不动刀:.gitignore 原样保留;.hidden.txt 末点照切只剩 .hidden;
  • 末尾点被当成扩展名:name. 变 name,连目录点 .. 都被削成一个 .;
  • 无点整串不动:README 仍是 README。

这一刀还不幂等:把 16 行输出粘回去跑第二遍,a.tar 继续变 a、archive.tar 继续变 archive,2 项变形;勾选扩展名那档二遍变化项 0、行数仍是 16。所以别把「取消包含扩展名」当成「去掉扩展名」,多跑一遍就多削一层。

去重:逐字比,大小写也算不同

去重按输出名精确匹配、含大小写:/a/photo.JPG、/b/photo.jpg、/c/PHOTO.JPG 勾上去重仍输出 3 行,统计显示 唯一文件名:3。夹具 16 到 14 靠 report.pdf 与 photo.JPG 各重复两次,photo.JPG 两行里一行带首尾空白,trim 后才并得起来。

盘符与 URL 根:交出的是另一种串

混进批量的非文件路径行都有固定结果:盘符根 C:\ 返回 2 字符的 C:,串里没点,取消扩展名也不动;URL 根的「文件名」其实是主机名,https://example.com/ 出 11 字符的 example.com,取消后剩 7 字符;没有斜杠的协议串整条当名字,mailto:support@example.com 原样 26 字符,取消扩展名削掉尾巴 .com 后剩 22 字符。函数不知道盘符、主机名、邮箱是什么,只会切段和找点。

200 行是一份 0.154 ms 的账

把同一份夹具复制 10 遍成 200 行 CRLF 输入、3758 字节,在批量提取文件名这个动作上实测一次 0.154 ms,输出 160 行,唯一文件名仍是 14;勾去重反而更快,0.1223 ms、14 行。行数账线性放大:总路径数 170、提取文件名 160。页面没有长度校验、没有截断。

几处容易看走眼的地方

Q:去重会把 photo.JPG 和 photo.jpg 并成一条吗?

不会,精确匹配且大小写敏感,三条全留,唯一文件名:3。

Q:示例按钮的内容能当基准吗?

能:示例 6 行输入 155 字符 / 163 字节、LF 分隔且结尾无换行,第 4 行是第 1 行的刻意重复;跑完输出 6 行、统计条 6 / 6 / 5,可作干净基准。

把这几格账带回去

这份夹具里 17、16、14、20 互相咬合:20 行进、3 行空白不计、1 行空名被吞、16 行出、两处重复并成 14。机制三点:结尾分隔符的回退只兜一格,出去的空串连统计都不进;「取消包含扩展名」按最后一个点下刀且不幂等;去重逐字比对、大小写敏感。清单不同数会变,对账还是这两个减法。

📎 相关文章

1 GB 文件由 1024 块拼成:任意大小文件生成的分块节奏、取消边界与三种填充字节 2026-11-04 encodeAll 一开,中文先变成 中:HTML 实体表覆盖与解码容错实测 2026-11-04 HTML 美化与压缩不是互逆:10 个样本的往返字节账实测 2026-11-04 粘贴 100 行分数,第 45 行被悄悄算成 1/4:约分这页的负号、空行和大数各归谁管 2026-11-03 把 3. 起步贴进 Markdown 转 HTML,为什么有序列表的编号只认第一个数 2026-11-03