版本号parsing的正则expression式

我有以下forms的版本号:

version.release.modification

版本,发布和修改是一组数字或'*'通配符。 此外,任何这些数字(和任何前面的)可能会丢失。

所以以下是有效的和parsing为:

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 

任何人都可以提供一个不太复杂的正则expression式来validation和检索版本号和修改号吗?

非常感谢!


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

基于OneByOne的回答(对我来说最简单),我添加了一些非捕获组(“(?:”部分 – 感谢VonC向我介绍非捕获组!),所以只捕获包含数字或*字符。

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

非常感谢大家!

我会表示格式为:

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

作为一个正则expression式,这是:

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

[编辑添加:这个解决scheme是一个简明的方法来validation,但有人指出,提取值需要额外的工作。 无论是通过使正则expression式复杂化还是通过处理匹配的组来处理这个问题都是一个问题。

在我的解决scheme中,这些组织捕获了"." 字符。 这可以像使用阿贝里的答案一样使用非捕获组来处理。

此外,即使组件数量less于三个,最右边的组也会捕获最后一个组件,因此,例如,双组件input会导致第一组和最后一组捕获,而中间一个组件未捕获。 我认为这可以由支持的非贪婪组织处理。

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

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

这并不比“分裂"."更短"." ]

使用正则expression式,现在你有两个问题。 我会分开点(“。”)的事情,然后确保每个部分是一个通配符或一组数字(正则expression式是完美的现在)。 如果事情是有效的,你只是返回正确的分块。

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

基于OneByOne的回答(对我来说最简单),我添加了一些非捕获组(“(?:”部分 – 感谢VonC向我介绍非捕获组!),所以只捕获包含数字或*字符。

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

非常感谢大家!

这可能工作:

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

在顶层,“*”是有效版本号的特殊情况。 否则,它以一个数字开始。 然后有零个,一个或两个“.nn”序列,然后是一个可选的“。*”。 这个正则expression式会接受1.2.3。*,在你的应用程序中可能允许也可能不允许。

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

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

我倾向于同意分裂的build议。

我已经在perl中为你的问题创build了一个“testing器”

 #!/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"; } 

电stream输出:

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

我的2美分:我有这种情况:我不得不从string文本parsing版本号。 (我知道这是非常不同的原始问题,但谷歌寻找parsing版本号的正则expression式显示此线程在顶部,所以在这里添加此答案)

所以string文字就像这样:“Service version 1.2.35.564 is running!”

我不得不从这个文字中parsing出1.2.35.564。 从@ajborley得到一个提示,我的正则expression式如下:

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

一个testing它的小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 } 

另一个尝试:

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

这给出了4,5,6组中的三个部分,但是:它们alignment到右边。 所以4,5或6中的第一个非空值给出版本字段。

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

这应该符合你的规定。 它取决于通配符的位置,是一个嵌套的正则expression式:

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

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

我见过很多答案,但是…我有一个新的答案。 它至less适用于我。 我已经添加了一个新的限制。 版本号无法启动(主要,次要或补丁)与任何零跟随其他。

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

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

它基于前一个。 但是,我看到这个解决scheme更好…对我来说;)

请享用!!!

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

与你的第一个例子完全一致,拒绝另外四个例子

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

你可以删除'(?ms)'
我用它来表示这个正则expression式通过QuickRex在多行应用

这也匹配1.2.3。*

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

我会build议不那么优雅的:

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

请记住,正则expression式是贪婪的,所以如果你只是在版本号string内search,而不是在一个更大的文本中,使用^和$来标记你的string的开始和结束。 格雷格的正则expression式似乎工作正常(只是在我的编辑器中快速尝试),但取决于您的库/语言,第一部分仍然可以匹配错误的版本号中的“*”。 也许我错过了一些东西,因为我一年左右没有使用正则expression式。

这应该确保你只能find正确的版本号码:

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

编辑:实际上格雷格已经添加了他们,甚至改善了他的解决scheme,我太慢了:)

看来很难有一个正则expression式正是你想要的(即只接受你需要的情况,拒绝所有其他的返回一些组的三个组件)。 我试了一下,想出了这个:

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

国际海事组织(我没有广泛的testing)这应该工作得很好,作为inputvalidation,但问题是,这个正则expression式不提供检索组件的方式。 为此,你仍然需要做一个分裂的时期。

这个解决scheme并不是一体的,但大多数时候在编程时并不需要。 当然,这取决于你在代码中可能有的其他限制。

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

也许更简洁的一个可能是:

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

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

另一个解决scheme:

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

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

我认为这是一个很好的练习 – vparse ,它有一个很小的来源 ,具有一个简单的function:

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

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

如果你对''不满意'。 结局,可能是你可以结合逻辑与endswith