2008-09-17 4 views
61

У меня есть номер версии следующего вида:Регулярное выражение для разбора номер версии

version.release.modification

, где версия, выпуск и модификация либо набор цифр или «*» подстановочные персонаж. Кроме того, любое из этих чисел (и любых предыдущих.) Может отсутствовать.

Так следующие справедливы и разобрать, как:

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 

Но они не являются годными:

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

Может кто-нибудь предоставить мне не слишком сложное регулярное выражение для проверки и получения освобождения , номера версий и модификаций?

+0

Im не уверен, что возможен «простой». – svrist 2008-09-17 11:11:05

ответ

51

Я бы выразить формат, как:

«1-3 разделенных точками компонентов, каждый числовой исключением того, что последний может быть *»

Как регулярное выражение, это:

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

[Изменить, чтобы добавить: это решение является кратким способом проверки, но это было указано, что извлечение значений требует дополнительной работы. Дело в том, нужно ли справляться с этим, усложняя регулярное выражение или обрабатывая согласованные группы.

В моем решении группы захватывают символы ".". Это можно рассматривать с использованием не-захватных групп, как в ответе аджборли.

Кроме того, самая правая группа будет захватывать последний компонент, даже если имеется менее трех компонентов, и поэтому, например, двухкомпонентный вход приводит к захвату первого и последнего групп, а средний не определен. Я думаю, что это могут быть решены не-жадные группы, где они поддерживаются.

Perl код для решения обоих вопросов после того, как регулярное выражение может быть что-то вроде этого:

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

Что на самом деле не меньше, чем любая расщеплению на "." ]

+0

Добавление некоторых не захватывающих групп (см. Мой ответ ниже) означает, что группы захвата не захватывают конечный «.». ^ (?: (\ D +) \.)? (?: (\ D +) \.)? (\ * | \ D +) $ Спасибо! – 2008-09-17 12:15:20

+0

Единственная проблема с этим - быть очень приятным и чистым предложением - заключается в том, что группы не правы, потому что 1,2 будут захватывать 1 в первом и 2 в третьей группе из-за жадности. – jrudolph 2008-09-17 12:16:04

10

Это может работать:

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

На верхнем уровне, «*» является частным случаем действительного номера версии. В противном случае он начинается с числа. Затем есть нулевая, одна или две последовательности «.nn», а затем необязательная «. *». Это регулярное выражение принимало бы 1.2.3. *, Которое может быть или не быть разрешено в вашей заявке.

Код для получения согласованных последовательностей, особенно часть (\.\d+){0,2}, будет зависеть от вашей конкретной библиотеки регулярных выражений.

+0

Отличный ответ! Я думаю, что вы должны поменять неэкономленный * на {0,2}, чтобы предотвратить соответствие 1.2.3.4. В зависимости от вашей библиотеки регулярных выражений вы можете приложить шаблон в^() $, если вы можете выполнять поиск, а не только совпадение. – 2008-09-17 11:29:21

+0

Хорошие моменты, я улучшил ответ. – 2008-09-17 11:38:14

+0

Незначительное изменение на^(\ * | \ d + (\. \ D +) {0,1} (?: (\. \ *)? | (\. \ D +)?)) $ Аннулирует 1.2.3.* слишком – Pieter 2008-09-17 11:47:30

36

Используйте регулярное выражение, и теперь у вас есть две проблемы. Я бы разделил вещь на точки ("."), Затем убедитесь, что каждая часть является либо подстановочным знаком, либо набором цифр (теперь регулярное выражение отлично). Если вещь верна, вы просто возвращаете правильный фрагмент раскола.

1

Имейте в виду регулярное выражение жадные , поэтому, если вы просто выполняете поиск в строке номера версии, а не в большом тексте, используйте^и $, чтобы отметить начало и конец строки. Регулярное выражение от Greg похоже работает нормально (просто быстро попробовал в моем редакторе), но в зависимости от вашей библиотеки/языка первая часть все равно может соответствовать «*» в неправильных номерах версий. Может быть, мне что-то не хватает, поскольку я не использовал Regexp в течение года или около того.

Это должно убедиться, что вы можете найти только правильные номера версий:

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

редактировать: на самом деле greg добавил их уже и даже улучшил его решение, я слишком медленный :)

+0

ouch да, не заметил этого - спасибо :) – FrankS 2008-09-17 12:05:05

4

Я склонен согласиться с предложением расслоения.

Ive создал "тестер" для вашей проблемы в 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"; 
} 

Токовый выход:

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

Было бы хорошо, так как OneByOne выглядит как самый простой. – jrudolph 2008-09-17 12:04:24

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

ли точно соответствовать ваши первые 6 примеров, и отвергает 4 других

  • группа 1: майор или майор.minor или ' *
  • группа 2, если существует: незначительные или *
  • группа 3, если существует: *

Вы можете удалить „(? Мс)“
Я использовал его, чтобы указать регулярное выражение для применения на многострочных линиях через QuickRex

5

Не знаю, на какой платформе вы находитесь, но в .NET есть класс System.Version, который будет анализировать номера версий nnnn для вас.

1

Это соответствует 1.2.3 * слишком

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

Я хотел бы предложить менее элегантна:

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

9

Спасибо за все ответы..! Это ace :)

Основываясь на ответе OneByOne (который выглядел как самый простой для меня), я добавил несколько не захватывающих групп (части «(?:» - благодаря VonC, чтобы представить меня неперехватывающим группам!), поэтому группы, которые занимаются захватом, содержат только цифры или символ *.

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

Большое спасибо всем!

2

Другая попытка:

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

Это дает три части в группах 4,5,6 НО: Они выравниваются по правому краю. Таким образом, первый ненулевой из 4,5 или 6 дает поле версии.

  • 1.2.3 дает 1,2,3
  • 1.2. * Дает 1,2 *
  • 1,2 дает нуль, 1,2
  • *** дает NULL, NULL, *
  • 1. * дает нуль, 1, *
1

Это кажется довольно трудно иметь регулярное выражение, которое делает именно то, что вы хотите (т.е. принимать только те случаи, которые вам нужны, и отвергать всех других и возвратите несколько групп для трех компонентов). Я дать ему попробовать и придумать с этим:

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

ИМО (я не оттестирован) это должно работать как валидатор для ввода, но проблема заключается в том, что это регулярное выражение не предлагают способ извлечения компонентов. Для этого вам все равно придется разделить период.

Это решение не все-в-одном, но в большинстве случаев в программировании его не нужно. Конечно, это зависит от других ограничений, которые могут возникнуть в вашем коде.

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

Возможно, более кратким один может быть:

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

Это может затем быть повышена до 1.2.3.4.5 * или ограничены в точности XYZ с помощью * или {2} вместо {0. , 2}

3

Это должно работать на то, что вы оговорили. Это зависит от дикой позиции карты и вложенное регулярное выражение:

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

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

2

Я видел много ответов, но ... У меня есть новый. Это работает для меня, по крайней мере. Я добавил новое ограничение. Номера версий не могут запускаться (основной, незначительный или патч) с любыми нулями, за которыми следуют другие.

01.0.0 не является действительным 1.0.0 действует 10.0.10 действует 1.0.0000 не является действительным

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

Он основан на предыдущей. Но я вижу это решение лучше ... для меня;)

Наслаждайтесь !!!

4

Мои 2 цента: У меня был такой сценарий: мне пришлось анализировать номера версий из строкового литерала. (Я знаю, что это сильно отличается от исходного вопроса, но поиск в Google для поиска регулярного выражения для разбора номера версии показал этот поток вверху, поэтому добавление этого ответа здесь)

Таким образом, строковый литерал будет выглядеть примерно так: Сервисная версия 1.2.35.564 работает! "

Мне пришлось разобрать 1.2.35.564 из этого литерала. Взяв пример с @ajborley, мой регулярное выражение выглядит следующим образом:

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

Маленький C# сниппет, чтобы проверить это выглядит, как показано ниже:

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

еще одно решение:

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

Задание Элементы 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> 
1

My take на это, как хорошее упражнение - vparse, который имеет tiny source, с простой функцией:

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

Я имел требование поиск/матч за номером версии, который следует Maven конвенции или даже просто одну цифру. Но никакого квалификатора в любом случае. Это было странно, что мне потребовалось время, то я пришел с этим:

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

Это гарантирует, что версию,

  1. начинающихся с цифрой
  2. Может иметь любое количество цифр
  3. Только цифры и. разрешены

Один из недостатков заключается в том, что версия может даже заканчиваться символом '.' Но он может обрабатывать неопределенную длину версии (сумасшедший версий, если вы хотите назвать)

Матчи:

  • 1.2.3
  • 1.09.5
  • 3.4.4.5.7.8.8 ,
  • 23.6.209.234.3

Если вы не недовольны ". возможно, вы можете комбинировать с логикой конца

Смежные вопросы