语义化版本号规范化:把 v1.2 和 1.2.0 归一成一份能比对的清单
讲清楚为什么 v1.2、1.2 和 1.2.0 必须先归一才能放心比对依赖,以及如何批量去 v 前缀、补全省略的修订段、去前导零,全程在浏览器本地完成,不上传任何版本列表。
语义化版本号规范化:把 v1.2 和 1.2.0 归一成一份能比对的清单
我做依赖审计时最常踩的坑,不是某个包真的有漏洞,而是同一个版本号被写成了三四种样子。一份从 package.json 抄出来的列表里,可能同时躺着 v1.2.3、1.2、1.02.0 和 1.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 明确禁止数字段带前导零,02和2必须当成同一个值。
这三件事看着琐碎,但只要列表上百行,手工改一定会漏。交给工具批量跑一遍,整列对齐,才是可靠的做法。
一个真实的输入输出例子
我拿一份混着各种写法的标签列表试过。输入是这样几行:
v1.2
1.2.0
1.02.0
v2.0.0
latest
规范化之后,前四行被改写并合并成:
1.2.0
2.0.0
v1.2、1.2.0、1.02.0 三行最终都归到 1.2.0,因为去掉 v、补全修订段、去掉前导零之后它们本来就是同一个版本,去重自然把重复折叠掉。而 latest 这一行根本没法套进 SemVer,工具不会强行编一个版本出来,而是把它单独标成无效项保留下来,提示我这一条得人工拍板。机械能处理的它处理,处理不了的它老实告诉你,这一点很重要。
数据不出浏览器
版本号清单经常藏着内部信息:私有仓库的标签、还没发布的灰度版本、客户环境里跑的具体版本。这类数据按规矩不该随手贴到一个会上传的在线工具里。所以我用的这个工具,解析、校验、补全、去重、导出全部在浏览器本地跑,上传的本地文本文件也是通过浏览器的 File API 在当前标签页读取,不会发到任何服务器。清洗带敏感信息的版本列表时,这一条是底线。
你可以亲自试一下 语义化版本号规范化工具,把你那份写法混乱的版本列表粘进去,看它怎么去 v、补段、去零再合并。如果你的目标只是把重复版本折叠掉,不需要改写形式,那 语义化版本号去重工具 会更直接。
一点收尾建议
规范化是依赖治理里最不起眼也最该先做的一步。它不解决"这个版本有没有漏洞"这种问题,但它保证你后续所有判断都建立在一份写法一致的清单上。我的习惯是:任何要进脚本、进数据库、进比对逻辑的版本列表,先过一遍归一,再做别的。导入前顺手下载一份带行号的 CSV 留底,哪天比对结果对不上,也能回去查是哪一行的写法出了岔子。把脏数据挡在比对之前,比在比对之后查 bug 省事得多。
Made by Toolora · Updated 2026-06-13