Pergunta

Eu tenho um número de versão do seguinte formulário:

versão.lançamento.modificação

onde versão, lançamento e modificação são um conjunto de dígitos ou o caractere curinga '*'.Além disso, qualquer um desses números (e qualquer . anterior) pode estar faltando.

Portanto, o seguinte é válido e analisado como:

1.23.456 = version 1, release 23, modification 456
1.23     = version 1, release 23, any modification
1.23.*   = version 1, release 23, any modification
1.*      = version 1, any release, any modification
1        = version 1, any release, any modification
*        = any version, any release, any modification

Mas estes não são válidos:

*.12
*123.1
12*
12.*.34

Alguém pode me fornecer um regex não muito complexo para validar e recuperar os números de lançamento, versão e modificação?

Foi útil?

Solução

Eu expressar o formato como:

"1-3 componentes separados por ponto, cada numéricos, exceto que o último pode ser *"

Como uma expressão regular, que é:

^(\d+\.)?(\d+\.)?(\*|\d+)$

[Edit para adicionar: esta solução é uma maneira concisa para validar, mas tem sido apontado que extrair os valores exige um trabalho extra. É uma questão de gosto se para lidar com isso, o que complica a regexp, ou processando os grupos combinados.

Na minha solução, os grupos capturar os personagens ".". Isso pode ser tratada com o uso de grupos de não captura como na resposta de ajborley.

Além disso, o grupo mais à direita irá capturar o último componente, mesmo se houver menos de três componentes, e assim, por exemplo, uma entrada de dois componentes resultados nos primeiros e últimos grupos de captura e o do meio indefinido. Acho que isso pode ser tratado por grupos não-gananciosos onde suportadas.

código Perl para lidar com ambas as questões após o regexp poderia ser algo como isto:

@version = ();
@groups = ($1, $2, $3);
foreach (@groups) {
    next if !defined;
    s/\.//;
    push @version, $_;
}
($major, $minor, $mod) = (@version, "*", "*");

Que não é realmente menor do que a divisão em "." ]

Outras dicas

Use regex e agora você tem dois problemas. eu iria dividir a coisa em pontos ( ""), então certifique-se de que cada parte ou é um curinga ou conjunto de dígitos (regex é perfeito agora). Se a coisa é válida, você acabou de voltar pedaço correto da divisão.

Este trabalho poder:

^(\*|\d+(\.\d+){0,2}(\.\*)?)$

No nível superior, "*" é um caso especial de um número de versão válido. Caso contrário, ele começa com um número. Depois, há zero, um, ou dois ".nn" sequências, seguido por uma opcional "*". Este regex aceitaria 1.2.3. * Que pode ou não pode ser permitido em sua aplicação.

O código para recuperar as seqüências combinados, especialmente a parte (\.\d+){0,2}, dependerá de sua biblioteca regex particular.

Obrigado por todas as respostas! Esta é ace:)

Com base na resposta de onebyone (que parecia o mais simples para mim), eu adicionei alguns grupos não capturar (as '(?:'! Partes - graças a VonC por me apresentar a grupos não-captura), de modo que os grupos que que captura contêm apenas os dígitos ou caractere *.

^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$

Muito obrigado a todos!

Não sei o que plataforma você está em mas em .NET há a classe System.Version que irá analisar os números de versão "n.n.n.n" para você.

Meus 2 centavos: Eu tive este cenário: Eu tive que analisar números de versão fora de um literal string. (Eu sei que isto é muito diferente da questão original, mas pesquisando para encontrar um regex para analisar o número da versão mostrou esta discussão no topo, assim que adicionar esta resposta aqui)

Assim, a cadeia literal seria algo como: "versão do Service 1.2.35.564 está em execução"

Eu tive que analisar o 1.2.35.564 fora deste literal. Tomando uma sugestão de @ajborley, meu regex é a seguinte:

(?:(\d+)\.)?(?:(\d+)\.)?(?:(\d+)\.\d+)

Uma pequena C # snippet para testar esta parece ser a seguir:

void Main()
{
    Regex regEx = new Regex(@"(?:(\d+)\.)?(?:(\d+)\.)?(?:(\d+)\.\d+)", RegexOptions.Compiled);

    Match version = regEx.Match("The Service SuperService 2.1.309.0) is Running!");
    version.Value.Dump("Version using RegEx");   // Prints 2.1.309.0        
}

Eu tendo a concordar com a sugestão de divisão.

Ive criou um "tester" para o seu problema em perl

#!/usr/bin/perl -w


@strings = ( "1.2.3", "1.2.*", "1.*","*" );

%regexp = ( svrist => qr/(?:(\d+)\.(\d+)\.(\d+)|(\d+)\.(\d+)|(\d+))?(?:\.\*)?/,
            onebyone => qr/^(\d+\.)?(\d+\.)?(\*|\d+)$/,
            greg => qr/^(\*|\d+(\.\d+){0,2}(\.\*)?)$/,
            vonc => qr/^((?:\d+(?!\.\*)\.)+)(\d+)?(\.\*)?$|^(\d+)\.\*$|^(\*|\d+)$/,
            ajb => qr/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/,
            jrudolph => qr/^(((\d+)\.)?(\d+)\.)?(\d+|\*)$/
          );

  foreach my $r (keys %regexp){
    my $reg = $regexp{$r};
    print "Using $r regexp\n";
foreach my $s (@strings){
  print "$s : ";

    if ($s =~m/$reg/){
    my ($main, $maj, $min,$rev,$ex1,$ex2,$ex3) = ("any","any","any","any","any","any","any");
    $main = $1 if ($1 && $1 ne "*") ;
    $maj = $2 if ($2 && $2 ne "*") ;
    $min = $3 if ($3 && $3 ne "*") ;
    $rev = $4 if ($4 && $4 ne "*") ;
    $ex1 = $5 if ($5 && $5 ne "*") ;
    $ex2 = $6 if ($6 && $6 ne "*") ;
    $ex3 = $7 if ($7 && $7 ne "*") ;
    print "$main $maj $min $rev $ex1 $ex2 $ex3\n";

  }else{
  print " nomatch\n";
  }
  }
print "------------------------\n";
}

A saída de corrente:

> perl regex.pl
Using onebyone regexp
1.2.3 : 1. 2. 3 any any any any
1.2.* : 1. 2. any any any any any
1.* : 1. any any any any any any
* : any any any any any any any
------------------------
Using svrist regexp
1.2.3 : 1 2 3 any any any any
1.2.* : any any any 1 2 any any
1.* : any any any any any 1 any
* : any any any any any any any
------------------------
Using vonc regexp
1.2.3 : 1.2. 3 any any any any any
1.2.* : 1. 2 .* any any any any
1.* : any any any 1 any any any
* : any any any any any any any
------------------------
Using ajb regexp
1.2.3 : 1 2 3 any any any any
1.2.* : 1 2 any any any any any
1.* : 1 any any any any any any
* : any any any any any any any
------------------------
Using jrudolph regexp
1.2.3 : 1.2. 1. 1 2 3 any any
1.2.* : 1.2. 1. 1 2 any any any
1.* : 1. any any 1 any any any
* : any any any any any any any
------------------------
Using greg regexp
1.2.3 : 1.2.3 .3 any any any any any
1.2.* : 1.2.* .2 .* any any any any
1.* : 1.* any .* any any any any
* : any any any any any any any
------------------------

Isso deve funcionar para o que você estipulado. Ele depende da posição do cartão selvagem e é um regex aninhada:

^((\*)|([0-9]+(\.((\*)|([0-9]+(\.((\*)|([0-9]+)))?)))?))$

http://imgur.com/3E492.png

Eu vi um monte de respostas, mas ... eu tenho um novo. Ele funciona para mim, pelo menos. Eu adicionei uma nova restrição. números de versão não pode iniciar (maior, menor ou adesivo) com quaisquer zeros seguido por outros.

01.0.0 não é válido 1.0.0 é válido 10.0.10 é válido 1.0.0000 não é válido

^(?:(0\\.|([1-9]+\\d*)\\.))+(?:(0\\.|([1-9]+\\d*)\\.))+((0|([1-9]+\\d*)))$

É baseado em um anterior. Mas eu vejo esta solução melhor ... para mim;)

Aproveite !!!

Outra tentativa:

^(((\d+)\.)?(\d+)\.)?(\d+|\*)$

Isto dá as três partes em grupos 4,5,6 MAS: Eles são alinhados à direita. Assim, o primeiro não-nula de 4,5 ou 6 dá o campo versão.

  • 1.2.3 dá 1,2,3
  • 1.2. * Dá 1,2, *
  • 1.2 dá nulo, 1,2
  • *** dá null, null, *
  • 1. * dá nulo, 1, *
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$

Talvez uma forma mais concisa um poderia ser:

^(?:(\d+)\.){0,2}(\*|\d+)$

Este pode então ser aprimorado para 1.2.3.4.5. * Ou restrito exatamente para x.y.z usando * ou {2} em vez de {0,2}

Eu tive uma exigência para pesquisar / corresponder para números de versão, que segue Maven convenção ou mesmo apenas um dígito. Mas nenhum qualificador em qualquer caso. Era peculiar, ele me levou tempo, então eu vim com isso:

'^[0-9][0-9.]*$'

Isso torna-se a versão,

  1. começa com um dígito
  2. Pode ter qualquer número de dígitos
  3. apenas dígitos e ''. são permitidos

Uma desvantagem é que a versão pode até mesmo acabar com '' Mas ele pode lidar com comprimento indefinido de versão (versioning louco se você quiser chamar assim)

Partidas:

  • 1.2.3
  • 1.09.5
  • 3.4.4.5.7.8.8.
  • 23.6.209.234.3

Se você não está satisfeito com '' terminando, pode ser que você pode combinar com a lógica endswith

(?ms)^((?:\d+(?!\.\*)\.)+)(\d+)?(\.\*)?$|^(\d+)\.\*$|^(\*|\d+)$

coincidir exatamente seus 6 primeiros exemplos, e rejeita os outros 4

  • grupo 1: maior ou major.minor ou '*'
  • grupo 2 se existe: menor ou *
  • grupo 3 se existe: *

Você pode remover '(? Ms)'
I é usado para indicar a esta expressão regular para ser aplicado em várias linhas através QuickRex

Esta corresponde 1.2.3. * Demasiado

^ (* |..? \ D + (\ d +) {0,2} (*)) $

Eu proporia a menos elegante:

(* | \ d + (\ d +) (*).?.?) |.. \ D + \ d + \ d +)

Tenha em mente regexp são gananciosos, por isso, se você está apenas à procura dentro da seqüência número da versão e não dentro de um grande texto, o uso ^ e $ para marcar início e fim da seqüência. A regexp de Greg parece funcionar bem (apenas deu-lhe uma rápida tentativa no meu editor), mas dependendo de sua biblioteca / idioma a primeira parte ainda pode igualar os "*" dentro dos números versão errada. Talvez eu estou faltando alguma coisa, como eu não usei Regexp por um ano ou assim.

Isso deve certificar-se de que você só pode encontrar números de versão corretos:

^ (\ * |..? \ D + (\ \ d +) * (\ \ *)) $

Edit: Na verdade greg adicionou-los já e até melhorou a sua solução, estou muito lento:)

Parece muito difícil ter uma regex que faz exatamente o que você quer (ou seja, aceitar apenas os casos que você precisa e rejeitar todas outros e retornar alguns grupos para o três componentes). Eu tenho experimentá-lo e chegar a isto:

^(\*|(\d+(\.(\d+(\.(\d+|\*))?|\*))?))$

IMO (Eu não testado extensivamente), este deve funcionar bem como um validador para a entrada, mas o problema é que essa regex não oferece uma maneira de recuperar os componentes. Por que você ainda tem que fazer uma divisão no período.

Esta solução não é tudo-em-um, mas que na maioria das vezes na programação não precisa. Claro que isso depende de outras restrições que você pode ter em seu código.

elementos Especificando XSD:

<xs:simpleType>
    <xs:restriction base="xs:string">
        <xs:pattern value="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}(\..*)?"/>
    </xs:restriction>
</xs:simpleType>

Minha opinião sobre isso, como um bom exercício - vparse , que tem um pequena fonte , com uma função simples:

function parseVersion(v) {
    var m = v.match(/\d*\.|\d+/g) || [];
    v = {
        major: +m[0] || 0,
        minor: +m[1] || 0,
        patch: +m[2] || 0,
        build: +m[3] || 0
    };
    v.isEmpty = !v.major && !v.minor && !v.patch && !v.build;
    v.parsed = [v.major, v.minor, v.patch, v.build];
    v.text = v.parsed.join('.');
    return v;
}

Mais uma solução:

^[1-9][\d]*(.[1-9][\d]*)*(.\*)?|\*$
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top