后缀乱就三档一起跑
月末清下载文件夹和照片备份目录,最乱的是后缀:JPG、jpg、Jpg 同层混着。我把文件名整段粘进后缀大小写页,三种档位各跑一遍——样本是自己列的一张清单:粘进去 20 段、有效 18 行,名字全是虚构的。
页面本体实测 211 行、8526 字节,convertExt 在第 88–113 行,三档共用同一句按下标拼串。这篇引的数全部出自 后缀大小写转换 这一页的纯函数返回值口径。
有些后缀转换完整行会变长
clip.ß 的后缀是 ß,1 枚码元;upper 档还回 SS 两枚,整串从 6 码元涨到 7 码元,可 UTF-8 字节数两边都是 7。
dot.İ 只有 lower 档会动:İ 被换成 i 加组合点,后缀 1 码元变 2,整串码元 5 到 6、字节 6 到 7;upper 档把它折回原字符,整行不动,记「未变化」。
mix.İß 是三档分歧的那一行:后缀 2 码元、整串 6 码元 8 字节——upper 给 7 码元仍 8 字节,lower 给 7 码元还 9 字节,title 一动不动。
落到我那 18 行有效清单上:upper 档变长 2 行、lower 档变长 2 行、title 档变长 1 行。
带点的名字不一定有后缀
名字长这样——a.、photo.、..、...、D:\dir.、.bashrc.、archive.tar.,最后一个点全卡在末尾,位置分别是 dot=1、5、1、2、6、7、11。第 92 行只挡 dot<=0,这些全被放行;第 97 行 substring(dot+1) 切出来是长度 0 的空串;第 138 行的 !r.ext 于是把它们和整行没点的名字归进同一格——「无后缀」与「未变化」两个计数器同时加一。7 条各跑 3 档共 21 次调用,返回值与入参逐字符相同。「从最后一个点起算」的判法我单独写过一篇,不在这儿复述。
| 名字 | dot | 切出的后缀 | 三档结果 |
|---|---|---|---|
photo. | 5 | 空串 | 三档全同入参 |
D:\dir. | 6 | 空串 | 三档全同入参 |
.bashrc. | 7 | 空串 | 三档全同入参 |
archive.tar. | 11 | 空串 | 三档全同入参 |
archive.tar.gz | 10 | gz | gz 照常换档 |
行首缩进会被悄悄吃掉
首尾空白在两处各被剪了一次:process 的第 134 行一次,convertExt 的第 89 行又来一次同一条正则。所以带 4 个行首空格和 1 个行尾制表符的一行,原始 22 码元,进到返回值里 before 已经是 17 码元。
只喂 convertExt 一处时,13 码元的 " photo.JPG " 出来 before 是 9 码元;词中间的空格剪不掉:20 码元的 " spaced name .TXT " 剪完 16 码元,点前面那个空格照旧留着。转换前列、转换后列、复制文本这三处,在函数返回值层是同一个剪好的串。
粘进去多少行不等于处理了多少个
清单粘进去 20 段,split(/\r?\n/) 得 20 段,进表只有 18 行:1 个纯空格段和 1 个空段在第 135 行被直接跳过。三档四数:
| 档位 | 总文件数 | 已转换 | 未变化 | 无后缀 |
|---|---|---|---|---|
| upper | 18 | 7 | 11 | 4 |
| lower | 18 | 8 | 10 | 4 |
| title | 18 | 8 | 10 | 4 |
已转换加未变化等于总文件数,在这张清单三档都成立:7+11=18、8+10=18。那句「已处理 18 个文件名」报的就是 total,不是粘贴段数 20。
表里的序号也不是粘贴位置:把 first.JPG、空行、second.TAR.gz、纯空格行、third.7z、尾随换行这 6 段喂进去,split 得 6 段、总文件数 3、有效原始行号 1,3,5,表格 # 列(第 158 行的 idx+1)连着排成 1,2,3。档位切换只在结果已经显示出来时才自动重跑(第 82–84 行),且第 131 行每次先清空旧结果,三档四数是三套独立计数而不是累加。
示例按钮灌的 7 行(第 190–198 行)是组现成对照。同一段文本,upper 只转 1 行、lower 转 5 行、title 转 6 行,已转换占比从 14.3% 一路涨到 85.7%。
表格里看到的和复制出来的不是同一份文本
表格单元格要过一道 escHtml(第 116–118 行):先 &、再 <、再 >、最后引号,四步连做。于是 all <>&".LOG 这个 12 码元的 after,在表格里是 27 码元的实体串;a<b>.TXT 从 8 码元变 14;quote".TXT 从 10 码元变 15。
复制走的是另一条路(第 185 行):只取每行的 after 这一个字段,用单个换行连接——不带序号列、不带转换前列、不经 escHtml。上面那个 12 码元的名字,复制出去还是 12 码元原串。
图 1:变长是码元层的账,字节是另一本,两本不同步
这页只产出文本,真要改名字是另一页 批量重命名 的事,本篇不替它写一个字。
文案里没提空行,也没提变长
把工具条目的文案逐条对了一遍,共 14 条判定:一致 6、部分一致 7、冲突 1。五行文案里没有「空行」二字,可 20 段粘贴对 total 18 的差,正是跳过空行行为给的账。名字长度没有上限:200 个 x 加 .JPG 共 204 码元照样整串吐回。空文本框、纯换行、4 个空格、剪出 5 段全是空行与空格的那一串,都被第 126 行的守卫拦下,只弹「请输入文件名」;第 153 行那句「无有效数据」在函数层拿不到输入,清空结果后再点复制,只弹「暂无结果可复制」。
FAQ
Q:文件名一个字没变,为什么有的记「已转换」有的记「未变化」?
判据只看返回串与入参是否逐字符全等。word.ς 的 upper 给 word.Σ,长度没变、码位变了,就是已转换;dot.İ 的 upper、roman.Ⅷ 的 upper 折叠回原字符,整行不动,记未变化。
Q:多出来的那一个字符是哪来的?
是大小写映射自己的返回值:ß 大写还给 SS、İ 小写还给 i 加一枚组合点,1 码元进 2 码元出。这一页按下标拼串、对返回值不做长度兜底,所以 clip.ß 的 upper 整串从 6 码元涨到 7,而 UTF-8 字节数停在 7。
Q:点在最末尾为什么算无后缀?
dot 大于 0 时 substring 从 dot+1 起切,切出空串,!r.ext 把它并进「无后缀」与「未变化」。同为 11 个字符长的名字,archive.tar. 报无后缀,archive.tar.gz 照常转 gz——差别只在最后一个点后面还有没有字符。
Q:表格里的那一行和复制出来的是同一串吗?
名字不含 &、<、>、引号时是同一串;含就有差——all <>&".LOG 在表格里是 27 码元实体,复制出去是 12 码元原文。屏幕实际渲染未实测,对账以复制文本为准。