111 votes

Une regex pour l'analyse 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 '*'. En outre, n'importe lequel de ces chiffres (et tout ce qui précède .) peut être manquant.

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

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 elles ne sont pas valables :

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

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

1 votes

Je ne suis pas sûr qu'une solution "simple" soit possible.

0 votes

Défi : quelqu'un est capable de produire une expression combinant toutes les réponses ci-dessous :)

131voto

Steve Jessop Points 166970

J'exprimerais le format comme suit :

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

Comme un regexp, c'est :

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

[Modification : cette solution est une manière concise 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 savoir s'il faut traiter cela en compliquant la regexp, ou en traitant les groupes correspondants.

Dans ma solution, les groupes capturent les "." personnages. Ce problème peut être résolu en utilisant des groupes de non-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, et donc, par exemple, une entrée à deux composants se traduit par la capture des premier et dernier groupes et par la non-définition du groupe du milieu. Je pense que ce problème peut être résolu par des groupes non gourmands lorsqu'ils sont supportés.

Le code Perl pour traiter les deux problèmes après le regexp 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 sur "." ]

1 votes

L'ajout de certains groupes non capturants (voir ma réponse ci-dessous) signifie que les groupes capturants ne capturent pas la queue '.'. ^(? :( \d +) \. ) ?(? :( \d +) \. ) ?(*| \d +)$ Merci !

0 votes

Le seul problème de cette proposition - qui est très belle et très propre - est que les groupes ne sont pas corrects, car 1,2 capturera 1 dans le premier groupe et 2 dans le troisième, par cupidité.

43voto

Paweł Hajdan Points 8004

Utilisez les regex et maintenant vous avez deux problèmes. Je diviserais le truc sur des points ("."), puis je m'assurerais que chaque partie est soit un joker, soit un ensemble de chiffres (les regex sont parfaits maintenant). Si la chose est valide, vous retournez juste le morceau correct de la division.

17voto

ajborley Points 425

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

En me basant sur la réponse de OneByOne (qui me semblait la plus simple), j'ai ajouté des groupes qui ne capturent pas (les parties '(?:') - merci à VonC de m'avoir fait découvrir les groupes qui ne capturent pas !

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

Merci à tous !

2 votes

Pourriez-vous plutôt ajouter ceci en tant que modification de votre question ? De cette façon, les bonnes réponses sont proches du sommet.

1 votes

Avec des noms de groupes : ^(? :(?<major> \d +) \. ) ?(? :(?<minor> \d +) \. ) ?(?<build>*| \d +)$

1 votes

Support de la semversion (un peu plus). - "1.2.3-alpha+abcdedf.lalal" -match "^(? :( \d +) \. ) ?(? :( \d +) \. ) ?(*| \d +) ?(?:\-([A-Za-z0-9 \. ]+))?(?:‌​\+([A-Za-z0-9 \. ]+))?$"

15voto

Greg Hewgill Points 356191

Ça pourrait marcher :

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

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

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

0 votes

Bonne réponse ! Je pense que vous devriez remplacer l'astérisque * par {0,2} pour éviter la correspondance 1.2.3.4. En fonction de votre bibliothèque de regexp, vous pouvez vouloir enfermer le motif dans ^(<pattern>)$ si vous ne pouvez faire qu'une recherche plutôt qu'une correspondance.

0 votes

Légère modification de ^(*||) \d +( \.\d +){0,1}(? :( \. *)?|( \.\d +) ?))$ invaliderait également 1.2.3.*.

2 votes

Pieter : Je pense que je vais m'arrêter là où je suis pour le moment. Cela devient rapidement le territoire "maintenant vous avez deux problèmes" :)

8voto

Duncan Smart Points 9195

Je ne sais pas sur quelle plateforme vous êtes, mais dans .NET, il existe la classe System.Version qui analyse les numéros de version "n.n.n.n" pour vous.

0 votes

Non, il est présent depuis la version 1.0.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X