跳到主要内容

语义化版本号规范化:把 v1.2 和 1.2.0 归一成一份能比对的清单

讲清楚为什么 v1.2、1.2 和 1.2.0 必须先归一才能放心比对依赖,以及如何批量去 v 前缀、补全省略的修订段、去前导零,全程在浏览器本地完成,不上传任何版本列表。

发布于 作者 李雷
#semver #版本号 #依赖管理 #开发工具

语义化版本号规范化:把 v1.2 和 1.2.0 归一成一份能比对的清单

我做依赖审计时最常踩的坑,不是某个包真的有漏洞,而是同一个版本号被写成了三四种样子。一份从 package.json 抄出来的列表里,可能同时躺着 v1.2.31.21.02.01.2.0。肉眼看它们都是 1.2 那一带,可一旦丢进脚本做字符串比对,四个值就是四个不同的字符串。结果就是该合并的没合并,该报警的被漏掉。语义化版本号规范化,做的就是把这堆写法不一的字符串改写成同一套形式,让后面的比对、去重、导入都建立在一致的基础上。

为什么 v1.2 和 1.2.0 必须先统一

SemVer 规范本身规定一个版本号由三段组成:主版本、次版本、修订号,中间用点分隔。但现实里写版本的人很随意。git tag 习惯加 v 前缀,Docker 镜像标签经常省掉修订段只写 1.2,有人手抄时还会带上前导零写成 01.2.0。这些写法在人看来是同一个版本,在程序看来却是完全不同的字符串。

依赖比对的核心是判断两个版本是不是同一个、谁更新。如果输入端的写法都不统一,比对逻辑要么得在每一处都兼容所有变体,要么就会误判。把归一这一步前置,后面无论是 === 还是版本排序,都只需要面对一种干净的三段式形式,逻辑反而简单。这就是先规范化再比对的价值。

规范化具体做了哪三件事

我平时主要靠三个动作把版本号拉齐:

  • v 前缀:v1.2.3 改写成 1.2.3。git tag 和 changelog 里的 v 是给人看的装饰,放进数据里就是噪音。
  • 补全省略的修订段:1.2 补成 1.2.0。只写两段的版本在 SemVer 里其实是不完整的,补上第三段后才能和标准的三段式版本放在一起比较。
  • 去前导零:1.02.0 改写成 1.2.0,01.2.0 改写成 1.2.0。SemVer 明确禁止数字段带前导零,022 必须当成同一个值。

这三件事看着琐碎,但只要列表上百行,手工改一定会漏。交给工具批量跑一遍,整列对齐,才是可靠的做法。

一个真实的输入输出例子

我拿一份混着各种写法的标签列表试过。输入是这样几行:

v1.2
1.2.0
1.02.0
v2.0.0
latest

规范化之后,前四行被改写并合并成:

1.2.0
2.0.0

v1.21.2.01.02.0 三行最终都归到 1.2.0,因为去掉 v、补全修订段、去掉前导零之后它们本来就是同一个版本,去重自然把重复折叠掉。而 latest 这一行根本没法套进 SemVer,工具不会强行编一个版本出来,而是把它单独标成无效项保留下来,提示我这一条得人工拍板。机械能处理的它处理,处理不了的它老实告诉你,这一点很重要。

数据不出浏览器

版本号清单经常藏着内部信息:私有仓库的标签、还没发布的灰度版本、客户环境里跑的具体版本。这类数据按规矩不该随手贴到一个会上传的在线工具里。所以我用的这个工具,解析、校验、补全、去重、导出全部在浏览器本地跑,上传的本地文本文件也是通过浏览器的 File API 在当前标签页读取,不会发到任何服务器。清洗带敏感信息的版本列表时,这一条是底线。

你可以亲自试一下 语义化版本号规范化工具,把你那份写法混乱的版本列表粘进去,看它怎么去 v、补段、去零再合并。如果你的目标只是把重复版本折叠掉,不需要改写形式,那 语义化版本号去重工具 会更直接。

一点收尾建议

规范化是依赖治理里最不起眼也最该先做的一步。它不解决"这个版本有没有漏洞"这种问题,但它保证你后续所有判断都建立在一份写法一致的清单上。我的习惯是:任何要进脚本、进数据库、进比对逻辑的版本列表,先过一遍归一,再做别的。导入前顺手下载一份带行号的 CSV 留底,哪天比对结果对不上,也能回去查是哪一行的写法出了岔子。把脏数据挡在比对之前,比在比对之后查 bug 省事得多。


Made by Toolora · Updated 2026-06-13