Question

J'ai un numéro de version du formulaire suivant:

version.release.modification

où version, release et modification sont soit un ensemble de chiffres, soit le caractère générique '*'. En outre, l’un de ces numéros (et l’un des chiffres précédents) peut être manquant.

Les éléments suivants sont valides et analysés comme suit:

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

Mais ceux-ci ne sont pas valides:

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

Quelqu'un peut-il me fournir un regex pas trop complexe pour valider et récupérer les numéros de version, de version et de modification?

Était-ce utile?

La solution

J'exprimerais le format sous la forme:

  

"1 à 3 composants séparés par des points, chaque nombre étant numérique, sauf que le dernier peut être *"

En tant qu’expression rationnelle, c’est:

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

[Modifier pour ajouter: cette solution est un moyen concis de valider, mais il a été souligné que l'extraction des valeurs nécessite un travail supplémentaire. C'est une question de goût s'il faut gérer cela en compliquant l'expression rationnelle ou en traitant les groupes correspondants.

Dans ma solution, les groupes capturent les caractères ". . Ceci peut être traité en utilisant des groupes sans capture comme dans la réponse d’Ajborley.

De plus, le groupe le plus à droite capturera le dernier composant, même s'il y a moins de trois composants. Ainsi, par exemple, une entrée à deux composants entraîne la capture du premier et du dernier groupe et le second du groupe indéfini. Je pense que cela peut être traité par des groupes non-gourmands où ils sont soutenus.

Le code Perl pour traiter les deux problèmes après l’expression rationnelle pourrait ressembler à ceci:

@version = ();
@groups = ($1, $2, $3);
foreach (@groups) {
    next if !defined;
    s/\.//;
    push @version, 

J'exprimerais le format sous la forme:

  

"1 à 3 composants séparés par des points, chaque nombre étant numérique, sauf que le dernier peut être *"

En tant qu’expression rationnelle, c’est:

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

[Modifier pour ajouter: cette solution est un moyen concis de valider, mais il a été souligné que l'extraction des valeurs nécessite un travail supplémentaire. C'est une question de goût s'il faut gérer cela en compliquant l'expression rationnelle ou en traitant les groupes correspondants.

Dans ma solution, les groupes capturent les caractères ". . Ceci peut être traité en utilisant des groupes sans capture comme dans la réponse d’Ajborley.

De plus, le groupe le plus à droite capturera le dernier composant, même s'il y a moins de trois composants. Ainsi, par exemple, une entrée à deux composants entraîne la capture du premier et du dernier groupe et le second du groupe indéfini. Je pense que cela peut être traité par des groupes non-gourmands où ils sont soutenus.

Le code Perl pour traiter les deux problèmes après l’expression rationnelle pourrait ressembler à ceci:

<*>

Ce qui n'est pas vraiment plus court que le fractionnement sur ".". ]

; } ($major, $minor, $mod) = (@version, "*", "*");

Ce qui n'est pas vraiment plus court que le fractionnement sur ".". ]

Autres conseils

Utilisez regex et vous avez maintenant deux problèmes. Je divisais l'élément en points ("."), puis je m'assurais que chaque partie correspond à un caractère générique ou à un ensemble de chiffres (regex est parfait maintenant). Si la chose est valide, il vous suffit de renvoyer le bon morceau du fractionnement.

Cela pourrait fonctionner:

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

Au niveau supérieur, " * " est un cas particulier d'un numéro de version valide. Sinon, cela commence par un nombre. Ensuite, il y a zéro, un ou deux ".nn". séquences, suivies d’un ". *" facultatif. Cette expression rationnelle accepterait 1.2.3. *, Ce qui peut ou non être autorisé dans votre application.

Le code permettant de récupérer les séquences correspondantes, en particulier la partie (\. \ d +) {0,2} , dépendra de votre bibliothèque regex particulière.

Merci pour toutes les réponses! C'est ace:)

Sur la base de la réponse de OneByOne (qui me paraissait la plus simple), j’ai ajouté des groupes ne capturant pas (les parties '(?:' - merci à VonC de m'avoir présenté des groupes non capturés!), de sorte que ne capturez que les chiffres ou le caractère *.

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

Merci beaucoup à tous!

Vous ne savez pas sur quelle plate-forme vous vous trouvez, mais dans .NET, la classe System.Version analyse "& n; n.n.n.n". numéros de version pour vous.

Mes 2 centimes: j'ai eu ce scénario: je devais analyser les numéros de version à partir d'un littéral chaîne. (Je sais que c'est très différent de la question initiale, mais googler pour trouver une expression rationnelle pour l'analyse du numéro de version a montré ce fil en haut, ajoutez donc cette réponse ici.

Le littéral de chaîne ressemblerait donc à quelque chose comme: "La version de service 1.2.35.564 est en cours d'exécution!"

J'ai dû analyser le 1.2.35.564 de ce littéral. En prenant exemple sur @ajborley, mon expression régulière est la suivante:

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

Un petit extrait de code C # à tester ressemble à ceci:

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        
}

J'ai tendance à être d'accord avec la suggestion de scission.

J'ai créé un "testeur". pour votre problème en 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";
}

Sortie actuelle:

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

Cela devrait fonctionner pour ce que vous avez stipulé. Il repose sur la position du caractère générique et est une expression rationnelle imbriquée:

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

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

J'ai vu beaucoup de réponses, mais ... j'en ai une nouvelle. Cela fonctionne pour moi au moins. J'ai ajouté une nouvelle restriction. Les numéros de version ne peuvent pas commencer (majeur, mineur ou correctif) par des zéros suivis par d'autres.

  

01.0.0 n'est pas valide   1.0.0 est valide   10.0.10 est valide   1.0.0000 n'est pas valide

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

Il est basé sur un précédent. Mais je vois mieux cette solution ... pour moi;)

Profitez !!!

Un autre essai:

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

Ceci donne les trois parties dans les groupes 4,5,6 MAIS: Ils sont alignés à droite. Donc, le premier non nul de 4,5 ou 6 donne le champ de version.

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

Peut-être un peu plus concis:

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

Ceci peut alors être amélioré à 1.2.3.4.5. * ou limité exactement à X.Y.Z en utilisant * ou {2} au lieu de {0,2}

J'étais obligé de rechercher / faire correspondre les numéros de version, conformément à la convention Maven ou même à un seul chiffre. Mais pas de qualification en tout cas. C’était étrange, cela m’a pris du temps, puis j’ai trouvé ceci:

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

Cela garantit que la version,

  1. commence par un chiffre
  2. Peut avoir n'importe quel nombre de chiffres
  3. Seuls les chiffres et '.' sont autorisés

Un inconvénient est que cette version peut même se terminer par "." Mais il peut gérer une longueur indéfinie de version (versioning fou si vous voulez l'appeler comme ça)

Correspondances:

  • 1.2.3
  • 1.09.5
  • 3.4.4.5.7.8.8.
  • 23.6.209.234.3

Si vous n'êtes pas mécontent de '.' se terminant, peut être vous pouvez combiner avec endswith logique

Cela garantit que la version,

  1. commence par un chiffre
  2. Peut avoir n'importe quel nombre de chiffres
  3. Seuls les chiffres et '.' sont autorisés

Un inconvénient est que cette version peut même se terminer par "." Mais il peut gérer une longueur indéfinie de version (versioning fou si vous voulez l'appeler comme ça)

Correspondances:

  • 1.2.3
  • 1.09.5
  • 3.4.4.5.7.8.8.
  • 23.6.209.234.3

Si vous n'êtes pas mécontent de '.' se terminant, peut être vous pouvez combiner avec endswith logique

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

Correspond exactement à vos 6 premiers exemples et rejette les 4 autres

  • groupe 1: majeur ou majeur.minor ou '*'
  • groupe 2 s'il existe: mineur ou *
  • groupe 3 s'il existe: *

Vous pouvez supprimer '(? ms)'
Je l'ai utilisé pour indiquer à cette expression rationnelle à appliquer sur plusieurs lignes via QuickRex

Ceci correspond à 1.2.3. * aussi

  

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

Je proposerais les moins élégants:

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

N'oubliez pas que les expressions rationnelles sont gourmandes. Par conséquent, si vous recherchez uniquement dans la chaîne du numéro de version et non dans un texte plus volumineux, utilisez ^ et $ pour marquer le début et la fin de votre chaîne. L’expression rationnelle de Greg semble bien fonctionner (je viens de l’essayer rapidement dans mon éditeur), mais selon votre bibliothèque / langue, la première partie peut toujours correspondre à "& *;" dans les mauvais numéros de version. Peut-être me manque-t-il quelque chose, car je n'ai pas utilisé Regexp depuis un an environ.

Cela devrait vous assurer que vous ne pouvez trouver que les bons numéros de version:

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

edit: en fait, greg les a déjà ajoutés et même amélioré sa solution, je suis trop lent:)

Il semble assez difficile d’avoir une expression régulière qui fasse exactement ce que vous voulez (c’est-à-dire accepter uniquement les cas dont vous avez besoin et rejeter tous les autres et renvoyer certains groupes pour le trois composants). J'ai essayé et je viens avec ceci:

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

IMO (je n’ai pas fait de tests approfondis) cela devrait fonctionner comme un validateur pour l’entrée, mais le problème est que cette expression régulière n’offre pas un moyen de récupérer les composants. Pour cela, vous devez encore diviser les points.

Cette solution n’est pas tout-en-un, mais la plupart du temps, elle n’a pas besoin de programmer. Bien entendu, cela dépend d'autres restrictions que vous pourriez avoir dans votre code.

Spécification d'éléments 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>

À mon avis, c'est un bon exercice - vparse , qui a un source minuscule , avec une fonction simple:

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;
}

Une autre solution:

^[1-9][\d]*(.[1-9][\d]*)*(.\*)?|\*$
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top