版本号解析的正则表达式

时间:2008-09-17 11:10:06

标签: regex versioning

我有以下格式的版本号:

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

有人能为我提供一个不太复杂的正则表达式来验证和检索版本,版本和修改号吗?

22 个答案:

答案 0 :(得分:71)

我将格式表示为:

  

“1-3个点分隔的组件,每个数字除了最后一个可能是*”

作为正则表达式,那是:

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

[编辑添加:此解决方案是一种简洁的验证方式,但有人指出,提取值需要额外的工作。无论是通过使正则表达式复杂化还是通过处理匹配的组来处理这个问题,都是一个品味问题。

在我的解决方案中,这些组捕获"."个字符。这可以使用非捕获组来处理,就像在ajborley的回答中一样。

此外,最右边的组将捕获最后一个组件,即使组件少于三个,因此例如双组件输入导致第一组和最后一组捕获而中间组未定义。我认为这可以由支持的非贪婪团体处理。

在regexp之后处理这两个问题的Perl代码可能是这样的:

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

这与"."上的分裂相比并不短 ]

答案 1 :(得分:38)

使用正则表达式,现在你有两个问题。我会把东西分成点(“。”),然后确保每个部分都是一个通配符或一组数字(正则表达式是完美的)现在)。如果该东西有效,你只需返回正确的分割块。

答案 2 :(得分:11)

感谢所有回复!这是王牌:)

基于OneByOne的答案(对我来说看起来最简单),我添加了一些非捕获组('(?:'部分 - 感谢VonC将我介绍给非捕获组!),所以这些组捕获只包含数字或*字符。

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

非常感谢大家!

答案 3 :(得分:11)

这可能有效:

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

在顶层,“*”是有效版本号的特例。否则,它以数字开头。然后有零个,一个或两个“.nn”序列,后跟一个可选的“。*”。此正则表达式将接受1.2.3。*,这可能会或可能不会在您的申请中被允许。

检索匹配序列的代码,尤其是(\.\d+){0,2}部分,取决于您的特定正则表达式库。

答案 4 :(得分:7)

不知道你在哪个平台,但在.NET中有System.Version类,它将为你解析“n.n.n.n”版本号。

答案 5 :(得分:6)

我的2美分:我遇到过这种情况:我不得不用字符串文字解析版本号。 (我知道这与原始问题有很大不同,但谷歌搜索找到解析版本号的正则表达式显示此顶部的线程,所以在这里添加这个答案)

因此,字符串文字将类似于:"服务版本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        
}

答案 6 :(得分:5)

我倾向于同意拆分建议。

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

答案 7 :(得分:4)

我见过很多答案,但是...我有一个新答案。它至少对我有用。我添加了一个新限制。版本号无法启动(主要版本,次要版本或补丁版本),其中任何零都会跟随其他零件。

  

01.0.0无效   1.0.0有效   10.0.10有效   1.0.0000无效

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

它基于前一个。但我觉得这个解决方案更好......对我来说;)

享受!!!

答案 8 :(得分:4)

这适用于您规定的内容。它取决于外卡位置,是一个嵌套的正则表达式:

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

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

答案 9 :(得分:3)

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

也许更简洁的可能是:

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

然后可以使用*或{2}代替{0,2}

将其增强到1.2.3.4.5。*或完全限制为X.Y.Z

答案 10 :(得分:3)

我要求搜索/匹配版本号,遵循maven约定或甚至只是一位数。但无论如何都没有限定词。这很奇怪,我花了很多时间才想到这个:

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

这确保了版本

  1. 以数字开头
  2. 可以包含任意数量的数字
  3. 只有数字和'。'允许
  4. 一个缺点是版本甚至可能以“。”结尾。但是它可以处理无限长的版本(疯狂的版本控制,如果你想称之为)

    匹配

    • 1.2.3
    • 1.09.5
    • 3.4.4.5.7.8.8。
    • 23.6.209.234.3

    如果你对''不满意。结束,也许你可以结合逻辑

    结束

答案 11 :(得分:3)

另一次尝试:

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

这给出了组中的三个部分4,5,6但是: 它们与右边对齐。因此,第一个非空的4,5或6给出了版本字段。

  • 1.2.3给出1,2,3
  • 1.2。*给1,2,*
  • 1.2给出null,1,2
  • ***给出null,null,*
  • 1. *给出null,1,*

答案 12 :(得分:2)

似乎很难有一个完全符合你想要的正则表达式(即只接受你需要的案例并拒绝所有其他返回一些组三个组成部分)。我试一试,想出这个:

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

IMO(我没有进行过广泛的测试)这应该可以作为输入的验证器正常工作,但问题是这个正则表达式不提供检索组件的方法。为此,你仍然需要分期。

这个解决方案并非一体化,但在编程中大多数时候都不需要。当然,这取决于您的代码中可能存在的其他限制。

答案 13 :(得分:2)

这匹配1.2.3。*太

  

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

我会建议不那么优雅:

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

答案 14 :(得分:2)

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

与您的6个第一个示例完全匹配,并拒绝其他4个

  • 第1组:主要或主要.minor或'*'
  • 第2组(如果存在):minor或*
  • 组3如果存在:*

您可以删除'(?ms)'
我用它来指示这个正则表达式通过QuickRex

应用于多行

答案 15 :(得分:2)

指定XSD元素:

Provider

答案 16 :(得分:2)

我认为这是一个很好的练习 - 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;
}

答案 17 :(得分:2)

请记住,regexp是贪婪的,所以如果你只是在版本号字符串中搜索而不是在更大的文本中搜索,请使用^和$来标记字符串的开头和结尾。 来自Greg的正则表达式似乎工作正常(只是在我的编辑器中快速尝试),但根据您的库/语言,第一部分仍然可以匹配错误版本号中的“*”。也许我错过了一些东西,因为我已经有一年左右没用过Regexp了。

这应该确保您只能找到正确的版本号:

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

编辑:实际上greg已经添加了它们甚至改进了他的解决方案,我太慢了:)

答案 18 :(得分:2)

对于解析遵循以下规则的版本号: -仅是数字和点 -不能以点开头或结尾 -不能在一起是两个点

这个骗了我。

^(\d+)((\.{1}\d+)*)(\.{0})$

有效的情况是:

1、0.1、1.2.1

答案 19 :(得分:1)

还有一个解决方案:

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

答案 20 :(得分:1)

有时版本号可能包含字母数字的次要信息(例如 1.2.0b 1.2.0-beta )。在这种情况下,我使用的是此正则表达式:

([0-9]{1,4}(\.[0-9a-z]{1,6}){1,5})

答案 21 :(得分:1)

我找到了,它对我有用:

/(\^|\~?)(\d|x|\*)+\.(\d|x|\*)+\.(\d|x|\*)+