用于版本号解析的正则表达式


84

我有以下形式的版本号:

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

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


我不确定“简单”的选择是否可行。
svrist

Answers:


96

我将格式表示为:

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

作为正则表达式,那就是:

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

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

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

同样,即使少于三个组件,最右边的组也将捕获最后一个组件,因此,例如,两分量的输入将导致第一个和最后一个组被捕获,而中间的一个则未定义。我认为可以通过支持的非贪婪团体来解决。

在正则表达式之后处理这两个问题的Perl代码可能是这样的:

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

实际上并没有比分割[ "." ]短


1
添加一些非捕获组(请参见下面的答案)意味着捕获组不会捕获尾随的'。^(?:(\ d +)\。)?(?:(\ d +)\。)?(* | \ d +)$谢谢!
Andrew Borley

这个问题的唯一问题-是一个非常好的和干净的建议-这些组是不正确的,因为由于贪婪,1.2将在第一组中捕获1,在第三组中捕获2。
jrudolph

39

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


11

这可能起作用:

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

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

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


好答案!我认为您应该将未转义的*替换为{0,2}以防止1.2.3.4匹配。如果您只能进行搜索而不是匹配,则可能需要将模式包含在^(<pattern>)$中,具体取决于您的正则表达式库。
戴夫·韦伯

稍微更改^(* | \ d +(\。\ d +){0,1}(?:(\。*)?|(\。\ d +)?))$也将使1.2.3。*无效
Pieter

2
彼得:我想我现在要停下来。这很快就进入了“现在有两个问题”领域。:)
Greg Hewgill

11

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

根据OneByOne的回答(对我而言,这似乎是最简单的),我添加了一些非捕获组(“(?:”部分-感谢VonC向我介绍了非捕获组!),因此仅捕获了这些组包含数字或*字符。

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

非常感谢大家!


1
您可以将其添加为问题的编辑内容吗?这样,正确的答案就接近顶部
svrist

1
组名称为:^(?:(?<major> \ d +)\。)?(?:(?<minor> \ d +)\。)?(?<build> * | \ d +)$
javacavaj

1
支持semversion(更多)。-“ 1.2.3-alpha + abcdedf.lalal” -match“ ^(?:(\ d +)\。)?(?:(\ d +)\。)?(* | \ d +)?(?:\- ([A-Za-z0-9 \。] +))?(?:\ +([A-Za-z0-9 \。] +))?$“
山姆

请注意,如果版本由单个数字组成,它将与第三个(\*|\d+)而不是第一个匹配^(?:(\d+)\.)?
Piotr Dobrogost

8

我的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        
}

我知道您正在描述一种替代情况和情况,但为了完整起见:SemVer'要求'版本字符串的格式X.Y.Z(因此正好是三部分),其中X和Y必须为非负整数,并且不其他前导零。参见semver.org
Jochem Schulenklopper

1
@JochemSchulenklopper,谢谢,我知道SemVer,尽管问题没有提及SemVer。
Sudhanshu Mishra

1
真正。一位同事向我提出了有关解析SemVer字符串的问题,以帮助我阅读答案。
Jochem Schulenklopper

7

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


不,它一直在那里,因为1.0版本
邓肯智能

5

我倾向于同意分开的建议。

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

那样很好,因为OneByOne的外观看起来最简单。
jrudolph

您也应该测试错误的。您错过了引用OneByOne的点。
jrudolph

用圆点和更多的正则
表达式

4

这应该符合您的规定。它取决于通配符位置,并且是嵌套的正则表达式:

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

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


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*)))$

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

请享用!!!


3

另一种尝试:

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

这给出了4,5,6组中的三个部分:但它们向右对齐。因此,4,5或6中的第一个非空值将给出version字段。

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

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

也许更简洁一些:

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

然后可以将其增强为1.2.3.4.5。*或使用*或{2}而不是{0,2}严格限制为XYZ


3

我有一个搜索/匹配版本号的要求,该版本号遵循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

如果您对'。'不满意。结尾,也许可以与逻辑结合


为了摆脱最后一位数字,也许您想尝试一下:(\d+)(.\d+)*
cassioso

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

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

  • 第1组:major或major.minor或'*'
  • 第2组(如果存在):未成年人或*
  • 第3组(如果存在):*

您可以删除“(?ms)”,
我用它来指示此正则表达式通过QuickRex应用于多行


2

这也匹配1.2.3。*

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

我会提出不太优雅的建议:

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


2

请记住,regexp是贪婪的,因此,如果您只是在版本号字符串中而不是在较大的文本中进行搜索,请使用^和$标记字符串的开始和结束。Greg的regexp似乎工作正常(在我的编辑器中进行了快速尝试),但是根据您的库/语言,第一部分仍可以在错误的版本号中匹配“ *”。也许我缺少了一些东西,因为我已经有大约一年没有使用Regexp了。

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

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

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


2

这似乎相当困难有不正是你想要什么正则表达式(即只接受你所需要的情况下,拒绝所有其他人,并返回一些团体3个成分)。我尝试一下,并提出以下建议:

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

IMO(我尚未进行广泛的测试),它可以很好地用作输入的验证器,但问题是此正则表达式无法提供检索组件的方法。为此,您仍然必须进行分割。

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


2

指定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>

2

我认为这是一个很好的练习-vparse,它的来源很小,但功能简单:

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

2

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

这个骗了我。

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

有效的情况是:

1,0.1,1.2.1



1

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

([0-9]{1,4}(\.[0-9a-z]{1,6}){1,5})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.