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

时间:2020-03-05 18:58:34  来源:igfitidea点击:

我有以下形式的版本号:

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

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

解决方案

回答

这可能起作用:

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

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

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

回答

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

回答

我将格式表示为:

"1-3 dot-separated components, each numeric except that the last one may be *"

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

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

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

在我的解决方案中,组捕获"。"字符。这可以通过使用非捕获组来解决,如ajborley的答案。

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

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

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

这实际上并不比在`"上分割要短。
]

回答

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

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

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

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

回答

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

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 =  if ( &&  ne "*") ;
    $maj =  if ( &&  ne "*") ;
    $min =  if ( &&  ne "*") ;
    $rev =  if ( &&  ne "*") ;
    $ex1 =  if ( &&  ne "*") ;
    $ex2 =  if ( &&  ne "*") ;
    $ex3 =  if ( &&  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
------------------------

回答

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

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

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

我们可以删除"(?ms)"
我用它来表示此正则表达式将通过QuickRex应用于多行

回答

不知道我们使用的平台是什么,但是.NET中有System.Version类,它将为我们解析" n.n.n.n"版本号。

回答

这也匹配1.2.3. *

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

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

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

回答

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

根据OneByOne的回答(对我来说,这似乎是最简单的),我添加了一些非捕获组(感谢VonC将我介绍给非捕获组,所以其中的'(?:'部分)!数字或者*字符。

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

非常感谢大家!

回答

另一种尝试:

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

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

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

回答

正则表达式似乎很难满足要求(即仅接受我们需要的情况,拒绝所有其他情况,并为这三个组成部分返回一些组),这似乎非常困难。我尝试一下,并提出以下建议:

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

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

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

回答

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

也许更简洁一些:

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

然后可以将其增强为1.2.3.4.5. 或者使用或者{2}而不是{0,2}严格限制为X.Y.Z

回答

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

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