Oh MyUtils

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']

相关工具