Semver计算器 - 语义版本解析、比较与测试 在线工具
解析、比较、排序语义版本字符串,并针对npm风格的范围进行测试。支持插入符、波浪号、通配符和OR范围 — 100%客户端运行,不向服务器发送任何数据。
常见问题
什么是语义版本控制(SemVer)?
语义版本控制是一种使用三部分数字格式的版本标准:MAJOR.MINOR.PATCH。MAJOR在不兼容的更改时递增,MINOR在向后兼容的新功能时递增,PATCH在向后兼容的错误修复时递增。它由SemVer 2.0.0规范定义,几乎在所有现代包生态系统中使用,包括npm、PyPI、Cargo和Go模块。
如何使用这个semver计算器工具?
根据需要选择四个标签之一:(1) 比较 — 输入两个版本查看大小,(2) 范围检查 — 输入版本和npm风格的范围进行测试,(3) 排序 — 粘贴多个版本按优先级排序,(4) 递增 — 输入版本查看下一个major、minor、patch和pre-release版本。
我的版本数据安全吗?会发送到服务器吗?
所有解析、比较和范围检查都在浏览器中使用JavaScript 100%客户端执行。不会向任何服务器传输数据。与查询npm注册表的工具不同,此工具完全离线工作。
插入符(^)和波浪号(~)范围有什么区别?
插入符(^)范围允许不修改最左非零数字的更改:^1.2.3表示>=1.2.3 <2.0.0。波浪号(~)范围仅允许补丁级别的更改:~1.2.3表示>=1.2.3 <1.3.0。对于0.x版本,插入符更严格:^0.2.3表示>=0.2.3 <0.3.0。
SemVer如何处理预发布版本?
预发布版本通过连字符添加(例如1.0.0-alpha、1.0.0-beta.1)。它们的优先级低于相关的正式版本,因此1.0.0-alpha < 1.0.0。标识符从左到右比较:数字标识符按整数比较,字母数字标识符按词典序比较。
什么是构建元数据?它会影响版本比较吗?
构建元数据通过加号添加(例如1.0.0+build.123)。根据SemVer 2.0.0规范,在确定版本优先级时必须忽略构建元数据。这意味着1.0.0+build.1和1.0.0+build.999被视为优先级相同。
我可以一次测试多个版本吗?
是的。在范围检查标签中,启用批量模式可以输入多个版本(每行一个)。工具将针对您的范围表达式测试每个版本,并显示颜色编码的结果。
代码示例
// Semantic Versioning Parser & Comparator
function parseSemVer(version) {
const match = version.trim().match(
/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([\w.]+))?(?:\+([\w.]+))?$/
);
if (!match) return null;
return {
major: parseInt(match[1], 10),
minor: parseInt(match[2], 10),
patch: parseInt(match[3], 10),
prerelease: match[4]
? match[4].split('.').map(id => /^\d+$/.test(id) ? parseInt(id, 10) : id)
: [],
build: match[5] ? match[5].split('.') : [],
};
}
function compareSemVer(a, b) {
for (const key of ['major', 'minor', 'patch']) {
if (a[key] > b[key]) return 1;
if (a[key] < b[key]) return -1;
}
if (a.prerelease.length > 0 && b.prerelease.length === 0) return -1;
if (a.prerelease.length === 0 && b.prerelease.length > 0) return 1;
const len = Math.max(a.prerelease.length, b.prerelease.length);
for (let i = 0; i < len; i++) {
if (i >= a.prerelease.length) return -1;
if (i >= b.prerelease.length) return 1;
const ai = a.prerelease[i], bi = b.prerelease[i];
if (ai === bi) continue;
if (typeof ai === 'number' && typeof bi === 'number') return ai < bi ? -1 : 1;
if (typeof ai === 'number') return -1;
if (typeof bi === 'number') return 1;
return ai < bi ? -1 : 1;
}
return 0;
}
function sortVersions(versions, ascending = true) {
return versions
.map(v => ({ raw: v, parsed: parseSemVer(v) }))
.filter(v => v.parsed !== null)
.sort((a, b) => compareSemVer(a.parsed, b.parsed) * (ascending ? 1 : -1))
.map(v => v.raw);
}
// Example
const versions = ['2.0.0', '1.0.0-alpha', '1.0.0', '1.2.3', '0.9.0'];
console.log('Sorted:', sortVersions(versions));
// ['0.9.0', '1.0.0-alpha', '1.0.0', '1.2.3', '2.0.0']