c++oding="utf-8" ?>
必须手写解析器而非仅靠正则:因正则无法可靠校验前导零、字段数(必须3段)、预发布段不能以“-”开头等硬性规则;需先剥离可选“v”前缀,再分段验证每段数字合法性、预发布和构建字段格式。

不能只靠正则表达式判断语义版本号是否合法——它容易漏掉前导零、字段数错误、预发布段非法开头等关键问题,生产环境必须手写解析器。
std::regex 初筛时为什么总匹配失败或误判
常见错误现象:std::regex_match("01.2.3", pattern) 返回 true(但 "01" 含前导零,非法);"1.2" 被放过(缺 PATCH 段);"v2.0.0-rc.1" 因 v 前缀未剥离直接匹配失败。
- 必须先用
string::substr()或string::starts_with("v")(C++20)剥离可选v前缀,再喂给正则 - 正则引擎在 GCC libstdc++ 7 及更早版本中存在 bug,
std::regex可能 crash 或漏匹配;Clang + libc++ 更可靠 - 推荐仅用正则做“快速初筛”,例如验证是否含非数字/点/连字符/加号以外的字符,而非完整校验
- 启用
std::regex_constants::ECMAScript和std::regex_constants::optimize,否则模式行为不稳定
手写解析器必须检查的四个硬性条件
语义版本号(SemVer 2.0.0)不是“看起来像就行”,以下任一不满足即非法:
- 按
'.'分割后,主版本部分必须恰好 3 段:major、minor、patch;"1.2.3.4"或"1.2"直接拒绝 - 每段数字字符串必须满足:
"0"合法,"00"、"01"非法;空字符串、含非 ASCII 数字字符(如全角 0)也非法 - 预发布段(
-后)需再按'.'拆分,每个子段不能为空,且不能以'-'开头("-alpha"非法,"alpha-1"合法) - 构建元数据(
+后)只校验字符集:[0-9a-zA-Z-_.],不解释语义,但不允许嵌套+或-
容易被忽略的边界 case 处理
这些 case 在测试中常被遗漏,但恰恰是 SemVer 规范明确禁止的:
-
"0.0.0+20240401"合法,但"0.0.0+"(+后无内容)非法 -
"1.0.0-alpha.beta"合法,但"1.0.0--alpha"(连续两个-)非法 -
"1.2.3-0"合法,"1.2.3-01"非法(预发布段内数字仍禁前导零) - UTF-8 字符串中混入 BOM(
\xEF\xBB\xBF1.2.3)必须先 strip,否则substr和find位置错乱 - 输入为空字符串、全空白、含
\0字符时,应提前返回false,避免后续split行为未定义
真正严格的语义版本校验,核心不在“怎么写正则”,而在“哪些规则必须由代码逻辑显式执行”——前导零、字段数、预发布段起始字符,这三类问题 regex 根本无力保证。手写解析器代码量并不大,但每一处判断都对应 SemVer 规范原文条款,调试和扩展也更直接。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











