版本号去重实战:semver 去重时怎么处理 v 前缀和省略段
整理依赖清单时,v1.2 和 1.2.0 其实是同一个版本,手工对比很容易漏。这篇讲清楚 semver 去重的规范化思路:补段、去 v 前缀后再比较,统计实际用了哪些版本,全程本地处理不上传。
版本号去重实战:semver 去重时怎么处理 v 前缀和省略段
整理一份依赖清单的时候,最烦的不是版本多,而是同一个版本写法不统一。v1.2、1.2.0、1.2.0+build 摆在一起,肉眼看像三条,实际可能指向同一个发布。如果你直接按字符串去重,这三条一条都不会合并,统计出来的"版本数"虚高,后面排查兼容性时还得返工。
我自己合并过几份来自不同同事的导出表:一份从 git tag 里 dump 出来,前面全带 v;一份从镜像仓库查询导出,只写了两段;还有一份从 Markdown 笔记里复制,混着构建元数据。三份加起来四百多行,真正不同的版本其实只有六十几个。靠 Excel 的去重功能完全合不拢,因为它认的是字符串完全相等。
这种活就交给 /zh/t/semantic-version-deduplicator/ 来做。它不是简单比字符串,而是先把每个版本号规范化,再判断是不是同一个版本。
为什么字符串去重对版本号不管用
语义化版本号有它自己的等价规则。v1.2.0 和 1.2.0 是同一个版本,v 只是标签习惯;1.2 在多数生态里等价于 1.2.0,省略的补丁段默认补 0。但这些等价关系,普通的去重逻辑一概不认。
更麻烦的是从网页或工单里复制来的文本,常带看不见的空白字符、零宽字符或者全角括号。它们在比较时算作不同字符,于是同一个 1.2.0 被拆成好几条。所以正确的顺序应该是:先规范化,再去重,而不是反过来。
规范化的三步:去 v、补段、统一比较
工具内部做的事可以拆成三步看清楚。
第一步去掉 v / V 前缀,把 v1.2.0 还原成 1.2.0。第二步补全省略的段,1.2 补成 1.2.0,让主版本、次版本、补丁三段都齐。第三步才拿规范化后的结果做比较,这样 1.2.0 和 v1.2.0 会被判定为同一个,只保留首次出现的那一行,并记下它在原文的行号。
预发布号和构建元数据不会被粗暴抹掉。1.0.0-beta.1 和 1.0.0 不是一回事,工具会保留差异;而 1.0.0+20130313144700 这种带构建元数据的,按 semver 规范在比较优先级时元数据不参与,但展示时仍保留,方便你回头追来源。
一个真实的输入输出例子
把下面这堆粘进去:
v1.2.0
1.2.0
1.2
1.2.0+build.7
2.0.0-rc.1
v2.0.0-rc.1
去重后输出是这样:
版本号 重复次数 首次出现行号
1.2.0 3 1
1.2.0+build.7 1 4
2.0.0-rc.1 2 5
前三条 v1.2.0、1.2.0、1.2 规范化后都是 1.2.0,合并成一条并显示重复 3 次。带构建元数据的那条因为元数据不同单独成行。两条 2.0.0-rc.1 合并成一条。一眼就能看出这份清单实际只用了三个不同的版本。
依赖清单整理:统计用了哪些版本
去重之后真正有用的,是那份"重复次数"统计。它直接告诉你某个版本在清单里出现了多少回,等于一份依赖使用频次表。哪个版本被引用最多、哪些是零散的一次性,排个序就清楚了。
输出格式可以在逐行、CSV、JSON、Markdown、SQL IN 和 TypeScript union 之间切换。要交给脚本继续处理就导 CSV,要写进类型定义就选 TypeScript union,不用自己手工补引号和逗号。无效项也能一起带出来复核,比如那些只写两段、或者预发布号拼错成 1.0.0-beta..1 的,留着它你就知道发布脚本会卡在哪一条。
本地处理,清单不出浏览器
依赖清单里有时混着内部包名、私有仓库地址,这类信息本来就不该往外传。这个工具的解析、规范化、去重、导出全部在浏览器本地完成,上传的文本文件通过 File API 在当前标签页读取,不会发到服务器。
如果只是想做单一动作,也有更专一的工具可选:只校验格式不去重用 /zh/t/semantic-version-list-validator/,只把版本号规范化用语义化版本号规范化工具就够了。按需取用,结果都一样留在本地。
整理版本号这件事看着琐碎,但一次没合干净,后面排查依赖冲突就得多绕几圈。先规范化再去重,把 v 前缀和省略段这两个坑填平,剩下的就是一份能直接交接的干净清单。
Made by Toolora · Updated 2026-06-13