我有以下形式的版本号:
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
任何人都可以为我提供一个不太复杂的正则表达式来验证和检索版本,版本和修改号码吗?
我将格式表达为:
"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, "*", "*");
这是不是真的比分裂的任何短"."
]
使用正则表达式,现在你有两个问题.我会把东西分成点("."),然后确保每个部分都是通配符或一组数字(正则表达式现在是完美的).如果该东西有效,您只需返回正确的分割块.
这可能有效:
^(\*|\d+(\.\d+){0,2}(\.\*)?)$
在顶层,"*"是有效版本号的特例.否则,它以数字开头.然后有零个,一个或两个".nn"序列,后跟一个可选的".*".此正则表达式将接受1.2.3.*,这可能会或可能不会在您的申请中被允许.
检索匹配序列的代码,尤其是(\.\d+){0,2}
部分,取决于您的特定正则表达式库.
感谢所有的回复!这是王牌:)
基于OneByOne的答案(对我来说看起来最简单),我添加了一些非捕获组('(?:'部分 - 感谢VonC向我介绍非捕获组!),因此只捕获组的组包含数字或*字符.
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$
非常感谢大家!
不知道你在哪个平台,但在.NET中有System.Version类,它将为你解析"nnnn"版本号.
我的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 }
我倾向于同意拆分建议.
我在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 ------------------------