有效的SemVer字符串必须严格匹配MAJOR.MINOR.PATCH格式,可选附加-prerelease或+build;需校验无前导零、标识符合法性及正确比较逻辑。

什么是有效的 SemVer 字符串
一个字符串要算作有效语义版本号,必须严格匹配 MAJOR.MINOR.PATCH 格式,且可选地附加 -prerelease(带点分隔的标识符)或 +build(带加号的元数据)。例如:1.2.3、0.10.0-rc.1、2.0.0+20240401 都合法;1.2、1.2.3.4、1.02.3、1.2.3-rc1(缺少点)都不合法。
用正则表达式快速校验(C++11 及以上)
C++ 标准库的 std::regex 足够应付 SemVer 的语法校验,但要注意:默认的 ECMAScript 引擎对 Unicode 不敏感,且某些编译器(如旧版 libstdc++)对重复量词支持不全。推荐用保守、可移植的正则:
^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9A-Za-z]+(?:\.[0-9A-Za-z]+)*))?(?:\+([0-9A-Za-z]+(?:\.[0-9A-Za-z]+)*))?$
使用时注意:
-
std::regex构造可能抛出std::regex_error,建议提前缓存静态 regex 对象 - 匹配需用
std::regex_match(不是regex_search),否则会误判"1.2.3abc"这类前缀匹配 - 不要依赖捕获组编号做逻辑分支——先确保整个字符串完全匹配,再按需提取字段
手动解析更可控(尤其嵌入式或禁用 regex 场景)
正则虽快,但无法区分 01.2.3(非法,含前导零)和 1.2.3(合法)。真正合规的 SemVer 要求每个数字段不能有前导零(除非就是 0)。这时必须逐段扫描:
立即学习“C++免费学习笔记(深入)”;
- 用
std::string_view划分'.'和'-'、'+'边界 - 对
MAJOR、MINOR、PATCH三段分别调用std::from_chars(C++17)或手写无前导零检查 +std::stoi -
prerelease段要求每个标识符非空、只含 ASCII 字母数字和连字符(-),且不能以连字符开头/结尾、不能连续出现 -
build段只校验字符合法性(字母数字和点),不解释含义
别忽略版本比较的实际需求
单纯判断“是否合法”往往只是第一步。如果你后续要排序或比较两个 SemVer 字符串(比如找最新版本),千万别直接用字典序——"2.10.0" 字典序小于 "2.9.0"。正确做法是:
- 拆出三段整数后,逐级比较
MAJOR→MINOR→PATCH - 若相等,再按规则比较 prerelease:无 prerelease 版本 > 有 prerelease;相同前缀下,数字段按数值比,字母段按字典序比(
"alpha" < "beta") - build 元数据**不参与比较**,即使存在也忽略
实际项目中,建议直接集成成熟小库(如 semverpp 或轻量 hand-rolled 解析器),避免在边界 case(如 1.0.0-01.1 vs 1.0.0-1.1)上反复踩坑。


















