Une expression régulière pour l’parsing du numéro de version

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 ‘*’. De plus, l’un de ces numéros (et tout précédent) peut être manquant.

Donc, 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 ce ne sont pas valables:

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

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

J’exprimerais le format comme suit:

“1-3 composants séparés par des points, chacun numérique sauf que le dernier peut être *”

En tant qu’expression rationnelle, c’est:

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

[Modifier pour append: 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 de gérer cela en compliquant l’expression rationnelle ou en traitant les groupes correspondants.

Dans ma solution, les groupes capturent le "." personnages. Cela peut être traité en utilisant des groupes non capturés comme dans la réponse de ajborley.

En outre, le groupe le plus à droite capturera le dernier composant, même s’il y a moins de trois composants. Par exemple, une entrée à deux composants génère le premier et le dernier groupe capturés et le second indéfini. Je pense que cela peut être traité par des groupes non gourmands là où ils sont pris en charge.

Le code Perl pour traiter les deux problèmes après l’expression rationnelle pourrait être quelque chose comme ceci:

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

Ce qui n’est pas vraiment plus court que de se séparer de "." ]

Utilisez regex et maintenant vous avez deux problèmes. Je diviserais la chose en points (“.”), Puis assurez-vous que chaque partie est soit un joker ou un ensemble de chiffres (regex est parfait maintenant). Si la chose est valide, vous retournez juste le morceau correct de la scission.

Cela pourrait fonctionner:

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

Au niveau supérieur, “*” est un cas particulier d’un numéro de version valide. Sinon, il commence par un chiffre. Ensuite, il y a zéro, une ou deux séquences “.nn”, suivies d’une option “. *”. Cette regex accepterait 1.2.3. * Qui peut ou non être autorisé dans votre application.

Le code pour 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 un as 🙂

Sur la base de la réponse de OneByOne (qui m’a semblé la plus simple), j’ai ajouté des groupes qui ne capturaient pas (les parties ‘(?:’ – grâce à VonC pour m’introduire dans des groupes non capturés!), contient les chiffres ou le caractère *.

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

Merci beaucoup tout le monde!

Je ne sais pas sur quelle plate-forme vous êtes, mais dans .NET, il y a la classe System.Version qui parsing les numéros de version “nnnn” pour vous.

J’ai tendance à être d’accord avec la suggestion partagée.

J’ai créé un “testeur” pour votre problème en perl

 #!/usr/bin/perl -w @ssortingngs = ( "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 (@ssortingngs){ 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 ------------------------ 

Mes 2 cents: J’avais ce scénario: je devais parsingr les numéros de version d’un littéral de chaîne. (Je sais que c’est très différent de la question originale, mais googler pour trouver une regex pour parsingr le numéro de version a montré ce fil en haut, ajoutant cette réponse ici)

Donc, le littéral de chaîne serait quelque chose comme: “La version de service 1.2.35.564 est en cours d’exécution!”

J’ai dû parsingr le 1.2.35.564 de ce littéral. En s’inspirant de @ajborley, ma regex est la suivante:

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

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

 void Main() { Regex regEx = new Regex(@"(?:(\d+)\.)?(?:(\d+)\.)?(?:(\d+)\.\d+)", RegexOptions.Comstackd); Match version = regEx.Match("The Service SuperService 2.1.309.0) is Running!"); version.Value.Dump("Version using RegEx"); // Prints 2.1.309.0 } 

Cela devrait fonctionner pour ce que vous avez stipulé. Il dépend de la position du joker et est une expression rationnelle nestede:

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

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

J’ai vu beaucoup de réponses, mais j’en ai une nouvelle. Ca marche au moins pour moi. J’ai ajouté une nouvelle ressortingction Les numéros de version ne peuvent pas démarrer (majeur, mineur ou patch) avec 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*)))$ 

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

Prendre plaisir!!!

Un autre essai:

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

Cela donne les trois parties dans les groupes 4,5,6 MAIS: Ils sont alignés à droite. Ainsi, 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, *

J’ai eu besoin de rechercher / faire correspondre les numéros de version, qui suivent la convention Maven ou même juste un seul chiffre. Mais aucun qualificatif dans tous les cas. C’était étrange, il m’a fallu du temps alors 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 de version indéfinie (versioning fou si vous voulez l’appeler ainsi)

Allumettes:

  • 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 ‘.’ fin, peut-être que vous pouvez combiner avec des fins avec la logique

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

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

  • groupe 1: major ou major.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

Cela correspond aussi à 1.2.3. *

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

Je proposerais le moins élégant:

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

Gardez à l’esprit que les expressions rationnelles sont gourmandes, donc si vous cherchez simplement dans la chaîne de numéro de version et non dans un texte plus grand, utilisez ^ et $ pour marquer le début et la fin de votre chaîne. L’expression rationnelle de Greg semble bien fonctionner (essayez simplement mon éditeur), mais en fonction de votre bibliothèque / langue, la première partie peut toujours correspondre au “*” dans les mauvais numéros de version. Je manque peut-être quelque chose, car je n’ai pas utilisé Regexp depuis un an ou deux.

Cela devrait vous assurer que vous ne pouvez trouver que des numéros de version corrects:

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

edit: effectivement greg les a déjà ajouté et même amélioré sa solution, je suis trop lent 🙂

Il semble assez difficile d’avoir une regex qui fasse exactement ce que vous voulez (c.-à-d. N’acceptez que les cas dont vous avez besoin et rejetez tous les autres et renvoyez certains groupes pour les trois composants). J’ai essayé et je viens avec ça:

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

IMO (je n’ai pas testé de manière approfondie) cela devrait fonctionner correctement en tant que validateur pour l’entrée, mais le problème est que cette regex n’offre pas un moyen de récupérer les composants. Pour cela, vous devez toujours faire une période de temps partagé.

Cette solution n’est pas tout-en-un, mais la plupart du temps, la programmation n’est pas nécessaire. Bien sûr, cela dépend d’autres ressortingctions que vous pourriez avoir dans votre code.

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

Peut-être un plus concis pourrait être:

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

Cela peut ensuite être amélioré à 1.2.3.4.5. * Ou limité exactement à XYZ en utilisant * ou {2} au lieu de {0,2}

Spécification des éléments XSD:

      

Mon sharepoint vue est un bon exercice – vparse , qui a une petite source , 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 solution de plus:

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