Mam numer wersji w następującym formularzu:
version.release.modification
gdzie wersja, wydanie i modyfikacja to zestaw cyfr lub znak wieloznaczny „*”. Ponadto może brakować któregokolwiek z tych numerów (i wszystkich poprzedzających).
Więc poniższe są prawidłowe i analizowane jako:
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
Ale te nie są ważne:
*.12
*123.1
12*
12.*.34
Czy ktoś może podać mi niezbyt skomplikowane wyrażenie regularne, aby zweryfikować i pobrać numery wydania, wersji i modyfikacji?
regex
versioning
Andrew Borley
źródło
źródło
Odpowiedzi:
Format bym wyraził jako:
Jako wyrażenie regularne to:
^(\d+\.)?(\d+\.)?(\*|\d+)$
[Edytuj, aby dodać: to rozwiązanie jest zwięzłym sposobem walidacji, ale zwrócono uwagę, że wyodrębnianie wartości wymaga dodatkowej pracy. To kwestia gustu, czy poradzić sobie z tym, komplikując wyrażenie regularne, czy przetwarzając dopasowane grupy.
W moim rozwiązaniu grupy chwytają
"."
postacie. Można sobie z tym poradzić przy użyciu grup bez przechwytywania, jak w odpowiedzi Ajborleya.Ponadto grupa znajdująca się najbardziej po prawej stronie przechwyci ostatni komponent, nawet jeśli jest mniej niż trzy komponenty, więc na przykład dwuskładnikowe wejście skutkuje przechwyceniem pierwszej i ostatniej grupy, a środkowej niezdefiniowanej. Myślę, że mogą sobie z tym poradzić niechciane grupy, jeśli są wspierane.
Kod Perla rozwiązujący oba problemy po wyrażeniu regularnym mógłby wyglądać mniej więcej tak:
@version = (); @groups = ($1, $2, $3); foreach (@groups) { next if !defined; s/\.//; push @version, $_; } ($major, $minor, $mod) = (@version, "*", "*");
Co tak naprawdę nie jest krótsze niż rozdzielenie się
"."
]źródło
Użyj wyrażenia regularnego, a teraz masz dwa problemy. Podzieliłbym rzecz na kropki („.”), A następnie upewniłem się, że każda część jest albo symbolem wieloznacznym, albo zestawem cyfr (wyrażenie regularne jest teraz doskonałe). Jeśli coś jest poprawne, po prostu zwracasz poprawny fragment podziału.
źródło
To może zadziałać:
^(\*|\d+(\.\d+){0,2}(\.\*)?)$
Na najwyższym poziomie „*” jest specjalnym przypadkiem prawidłowego numeru wersji. W przeciwnym razie zaczyna się od liczby. Następnie jest zero, jedna lub dwie sekwencje „.nn”, po których następuje opcjonalny „. *”. To wyrażenie regularne akceptuje 1.2.3. *, Co może być dozwolone w Twojej aplikacji lub nie.
Kod do pobierania dopasowanych sekwencji, zwłaszcza
(\.\d+){0,2}
części, będzie zależał od konkretnej biblioteki wyrażeń regularnych.źródło
Dzięki za wszystkie odpowiedzi! To jest as :)
W oparciu o odpowiedź OneByOne (która wydawała mi się najprostsza) dodałem kilka grup nieprzechwytywanych (części „(?:” - dzięki VonC za wprowadzenie mnie do grup nieprzechwytujących!), Więc grupy, które przechwytują zawierać cyfry lub znak *.
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$
Wiele dzięki wszystkim!
źródło
(\*|\d+)
nie pierwsza^(?:(\d+)\.)?
grupa.Moje 2 centy: miałem taki scenariusz: musiałem przeanalizować numery wersji z literału ciągu. (Wiem, że to bardzo różni się od pierwotnego pytania, ale wyszukiwanie wyrażenia regularnego w celu przeanalizowania numeru wersji pokazało ten wątek u góry, więc dodałem tę odpowiedź tutaj)
Tak więc literał ciągu wyglądałby tak: „Usługa w wersji 1.2.35.564 jest uruchomiona!”
Musiałem przeanalizować 1.2.35.564 z tego dosłownego. Biorąc wskazówkę z @ajborley, moje wyrażenie regularne wygląda następująco:
(?:(\d+)\.)?(?:(\d+)\.)?(?:(\d+)\.\d+)
Mały fragment kodu C # do przetestowania wygląda jak poniżej:
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 }
źródło
X.Y.Z
(czyli dokładnie trzy części), gdzie X i Y muszą być nieujemnymi liczbami całkowitymi i nie dodatkowe zera wiodące. Zobacz semver.org .Nie wiem, na jakiej platformie jesteś, ale w .NET jest klasa System.Version, która przeanalizuje dla Ciebie numery wersji „nnnn”.
źródło
Zgadzam się z podzieloną sugestią.
Stworzyłem „testera” dla twojego problemu w perlu
#!/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"; }
Wyjście prądowe:
> 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 ------------------------
źródło
To powinno działać zgodnie z ustaleniami. Opiera się na pozycji dzikiej karty i jest zagnieżdżonym wyrażeniem regularnym:
^((\*)|([0-9]+(\.((\*)|([0-9]+(\.((\*)|([0-9]+)))?)))?))$
źródło
Widziałem wiele odpowiedzi, ale ... mam nową. Przynajmniej na mnie działa. Dodałem nowe ograniczenie. Numery wersji nie mogą zaczynać się od zer, po których następują inne.
^(?:(0\\.|([1-9]+\\d*)\\.))+(?:(0\\.|([1-9]+\\d*)\\.))+((0|([1-9]+\\d*)))$
Jest oparty na poprzednim. Ale widzę to rozwiązanie lepiej ... dla mnie;)
Cieszyć się!!!
źródło
Kolejna próba:
^(((\d+)\.)?(\d+)\.)?(\d+|\*)$
To daje trzy części w grupach 4,5,6 ALE: Są wyrównane do prawej strony. Zatem pierwsza niezerowa wartość 4,5 lub 6 daje pole wersji.
źródło
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$
Być może bardziej zwięzły mógłby być:
^(?:(\d+)\.){0,2}(\*|\d+)$
Można to następnie ulepszyć do 1.2.3.4.5. * Lub ograniczyć dokładnie do XYZ za pomocą * lub {2} zamiast {0,2}
źródło
Miałem wymóg wyszukiwania / dopasowywania numerów wersji, zgodnie z konwencją maven lub nawet pojedynczej cyfry. Ale w żadnym wypadku nie ma kwalifikatora. To było dziwne, zajęło mi trochę czasu, a potem wymyśliłem to:
'^[0-9][0-9.]*$'
Daje to pewność, że wersja
Jedną z wad jest to, że wersja może nawet kończyć się na „.” Ale może obsłużyć nieokreśloną długość wersji (szalone wersjonowanie, jeśli chcesz to tak nazwać)
Mecze:
Jeśli nie jesteś niezadowolony z „.” kończąc, może można połączyć z końcami z logiką
źródło
(\d+)(.\d+)*
(?ms)^((?:\d+(?!\.\*)\.)+)(\d+)?(\.\*)?$|^(\d+)\.\*$|^(\*|\d+)$
Dokładnie pasuje do 6 pierwszych przykładów i odrzuca 4 pozostałe
Możesz usunąć '(? Ms)'
Użyłem go do wskazania tego wyrażenia regularnego, które ma być zastosowane w wielu wierszach za pomocą QuickRex
źródło
To pasuje również do 1.2.3. *
Proponuję mniej eleganckie:
(* | \ d + (. \ d +)? (. *)?) | \ d +. \ d +. \ d +)
źródło
Pamiętaj, że wyrażenia regularne są chciwe, więc jeśli szukasz tylko w ciągu numeru wersji, a nie w większym tekście, użyj ^ i $, aby zaznaczyć początek i koniec łańcucha. Wyrażenie regularne od Grega wydaje się działać dobrze (po prostu wypróbowałem je w moim edytorze), ale w zależności od biblioteki / języka pierwsza część może nadal dopasować „*” w niewłaściwych numerach wersji. Może czegoś mi brakuje, ponieważ nie używałem Regexp od około roku.
Powinno to zapewnić, że możesz znaleźć tylko prawidłowe numery wersji:
^ (\ * | \ d + (\. \ d +) * (\. \ *)?) $
edycja: właściwie greg już je dodał i nawet poprawił swoje rozwiązanie, jestem za wolny :)
źródło
Wydaje się dość trudne, aby mieć wyrażenie regularne, które robi dokładnie to, czego chcesz (tj. Akceptuje tylko te przypadki, których potrzebujesz, a wszystkie inne odrzuca i zwraca niektóre grupy dla trzech składników). Spróbowałem i wymyśliłem to:
^(\*|(\d+(\.(\d+(\.(\d+|\*))?|\*))?))$
IMO (nie testowałem szczegółowo) to powinno działać dobrze jako walidator dla danych wejściowych, ale problem polega na tym, że to wyrażenie regularne nie oferuje sposobu na odzyskanie komponentów. W tym celu nadal musisz zrobić podział na okres.
To rozwiązanie nie jest kompleksowe, ale w większości przypadków w programowaniu nie musi. Oczywiście zależy to od innych ograniczeń, które możesz mieć w swoim kodzie.
źródło
Określanie elementów 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>
źródło
Przyjmuję to jako dobre ćwiczenie - vparse , które ma maleńkie źródło , z prostą funkcją:
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; }
źródło
W przypadku analizowania numerów wersji, które są zgodne z następującymi regułami: - są tylko cyframi i kropkami - nie mogą zaczynać się ani kończyć kropką - nie mogą składać się z dwóch kropek
Ten mnie załatwił.
^(\d+)((\.{1}\d+)*)(\.{0})$
Prawidłowe przypadki to:
1, 0,1, 1.2.1
źródło
Jeszcze jedno rozwiązanie:
^[1-9][\d]*(.[1-9][\d]*)*(.\*)?|\*$
źródło
Czasami numery wersji mogą zawierać pomniejsze informacje alfanumeryczne (np. 1.2.0b lub 1.2.0-beta ). W tym przypadku używam tego wyrażenia regularnego:
([0-9]{1,4}(\.[0-9a-z]{1,6}){1,5})
źródło
Znalazłem to i działa dla mnie:
/(\^|\~?)(\d|x|\*)+\.(\d|x|\*)+\.(\d|x|\*)+
źródło