Ferramentas / Validador de versão SemVer

Validador de versão SemVer

Digite uma versão semântica (ex.: 1.4.2-beta.1+build.5), compare com outra e ordene listas de versões.


Processamento local: nada do que você digita sai do seu navegador.

Como usar

Digite uma versão no campo A para validá-la e ver cada parte (MAJOR, MINOR, PATCH, pré-lançamento e build). Preencha também o campo B para saber qual das duas é maior. Na caixa de baixo, cole várias versões (uma por linha) para ordená-las da menor para a maior; as inválidas são listadas com o motivo.

Regras do SemVer 2.0.0

  • Formato MAJOR.MINOR.PATCH, com números inteiros sem zero à esquerda.
  • Pré-lançamento vem após hífen (1.0.0-rc.1) e tem precedência menor que a versão final.
  • Metadados de build vêm após + e são ignorados na comparação.
  • Identificadores numéricos do pré-lançamento são comparados como números (beta.2 < beta.11) e valem menos que os alfanuméricos.
  • O prefixo v (como em v1.2.3) é comum em tags do Git, mas não faz parte da especificação.

Como implementar em código

Exemplos prontos para usar no seu projeto.

// Expressão regular oficial do SemVer 2.0.0 (semver.org)
const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;

function parseSemver(v) {
  const m = SEMVER.exec(v);
  if (!m) return null;
  return { major: +m[1], minor: +m[2], patch: +m[3], pre: m[4] ?? null, build: m[5] ?? null };
}

console.log(parseSemver('1.4.2-beta.1+build.5')); // { major: 1, minor: 4, patch: 2, pre: 'beta.1', build: 'build.5' }
console.log(parseSemver('01.0.0'));               // null (zero à esquerda)
console.log(parseSemver('v1.0.0'));               // null (prefixo v)

Para comparar e ordenar use o pacote npm semver (semver.compare, semver.sort).

import re

# Expressão regular oficial do SemVer 2.0.0 (semver.org)
SEMVER = re.compile(
    r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$")

def parse_semver(v: str):
    m = SEMVER.match(v)
    if not m:
        return None
    major, minor, patch, pre, build = m.groups()
    return {"major": int(major), "minor": int(minor), "patch": int(patch), "pre": pre, "build": build}

print(parse_semver("1.4.2-beta.1+build.5"))  # {'major': 1, 'minor': 4, 'patch': 2, 'pre': 'beta.1', 'build': 'build.5'}
print(parse_semver("01.0.0"))                # None
print(parse_semver("v1.0.0"))                # None

Para comparar e ordenar use o pacote semver (semver.Version.parse).

package main

import (
	"fmt"
	"regexp"
)

// Expressão regular oficial do SemVer 2.0.0 (semver.org)
var semver = regexp.MustCompile(`^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`)

func main() {
	for _, v := range []string{"1.4.2-beta.1+build.5", "01.0.0", "v1.0.0"} {
		m := semver.FindStringSubmatch(v)
		if m == nil {
			fmt.Println(v, "-> inválida")
			continue
		}
		fmt.Printf("%s -> major=%s minor=%s patch=%s pre=%q build=%q\n", v, m[1], m[2], m[3], m[4], m[5])
	}
}

Para comparar versões use golang.org/x/mod/semver (exige o prefixo v) ou github.com/Masterminds/semver.

// Expressão regular oficial do SemVer 2.0.0 (semver.org)
final semver = RegExp(
    r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$");

void main() {
  for (final v in ['1.4.2-beta.1+build.5', '01.0.0', 'v1.0.0']) {
    final m = semver.firstMatch(v);
    if (m == null) {
      print('$v -> inválida');
    } else {
      print('$v -> major=${m[1]} minor=${m[2]} patch=${m[3]} pre=${m[4]} build=${m[5]}');
    }
  }
}

Para comparar versões use o pacote pub_semver (Version.parse).

import java.util.regex.*;

public class SemverCheck {
    // Expressão regular oficial do SemVer 2.0.0 (semver.org)
    static final Pattern SEMVER = Pattern.compile(
        "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");

    public static void main(String[] args) {
        for (String v : new String[]{"1.4.2-beta.1+build.5", "01.0.0", "v1.0.0"}) {
            Matcher m = SEMVER.matcher(v);
            if (!m.matches()) {
                System.out.println(v + " -> inválida");
                continue;
            }
            System.out.println(v + " -> major=" + m.group(1) + " minor=" + m.group(2) + " patch=" + m.group(3)
                    + " pre=" + m.group(4) + " build=" + m.group(5));
        }
    }
}

Para comparar versões use a biblioteca java-semver ou semver4j.

<?php
// Expressão regular oficial do SemVer 2.0.0 (semver.org)
const SEMVER = '~^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$~';

function parseSemver(string $v): ?array {
    if (!preg_match(SEMVER, $v, $m)) return null;
    return ['major' => (int)$m[1], 'minor' => (int)$m[2], 'patch' => (int)$m[3],
            'pre' => $m[4] ?? null, 'build' => $m[5] ?? null];
}

print_r(parseSemver('1.4.2-beta.1+build.5'));
var_dump(parseSemver('01.0.0')); // NULL
var_dump(parseSemver('v1.0.0')); // NULL

Para comparar versões, version_compare() do PHP aceita a maioria dos formatos semânticos.

using System;
using System.Text.RegularExpressions;

class Program
{
    // Expressão regular oficial do SemVer 2.0.0 (semver.org)
    static readonly Regex Semver = new(
        @"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$");

    static void Main()
    {
        foreach (var v in new[] { "1.4.2-beta.1+build.5", "01.0.0", "v1.0.0" })
        {
            var m = Semver.Match(v);
            if (!m.Success) { Console.WriteLine($"{v} -> inválida"); continue; }
            Console.WriteLine($"{v} -> major={m.Groups[1]} minor={m.Groups[2]} patch={m.Groups[3]} pre={m.Groups[4]} build={m.Groups[5]}");
        }
    }
}

Para comparar versões use o pacote NuGet Semver (SemVersion.Parse).

Perguntas frequentes

Por que v1.2.3 é considerada inválida?

A especificação SemVer não inclui o prefixo v. Muitas ferramentas o aceitam como conveniência, mas o formato oficial é 1.2.3. Retire o v para validar.

Duas versões que só diferem no build são iguais?

Na precedência sim: 1.0.0+a e 1.0.0+b são tratadas como equivalentes, pois a especificação manda ignorar os metadados de build ao comparar.

Qual versão é maior, 1.0.0-rc.1 ou 1.0.0?

1.0.0 é maior. Qualquer pré-lançamento tem precedência menor do que a versão normal correspondente.

Veja também

Precisa de um sistema ou app sob medida?

A VcInova desenvolve software, aplicativos e integrações para empresas de todo o Brasil.

Fale com a VcInova