버전 번호 구문 분석을위한 정규식
다음 형식의 버전 번호가 있습니다.
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의 답변에서와 같이 비 캡처 그룹을 사용하여 처리 할 수 있습니다.
또한 가장 오른쪽 그룹은 세 개 미만의 구성 요소가 있더라도 마지막 구성 요소를 캡처하므로 예를 들어 두 구성 요소 입력은 첫 번째 및 마지막 그룹이 캡처되고 중간 그룹은 정의되지 않습니다. 나는 욕심이없는 그룹이 지원을 받으면 처리 할 수 있다고 생각합니다.
정규 표현식 이후 두 문제를 모두 처리하는 Perl 코드는 다음과 같습니다.
@version = ();
@groups = ($1, $2, $3);
foreach (@groups) {
next if !defined;
s/\.//;
push @version, $_;
}
($major, $minor, $mod) = (@version, "*", "*");
쪼개지는 것보다 더 짧지는 않네요 "."
]
정규식을 사용하면 이제 두 가지 문제가 있습니다. 점 ( ".")으로 분할 한 다음 각 부분이 와일드 카드 또는 숫자 집합인지 확인합니다 (정규식은 이제 완벽합니다). 일이 유효하면 분할의 올바른 청크를 반환합니다.
이것은 작동 할 수 있습니다.
^(\*|\d+(\.\d+){0,2}(\.\*)?)$
최상위 수준에서 "*"는 유효한 버전 번호의 특별한 경우입니다. 그렇지 않으면 숫자로 시작합니다. 그런 다음 0 개, 1 개 또는 2 개의 ".nn"시퀀스가 있고 그 뒤에 선택적 ". *"가 있습니다. 이 정규식은 응용 프로그램에서 허용되거나 허용되지 않을 수있는 1.2.3. *을 허용합니다.
일치하는 시퀀스, 특히 (\.\d+){0,2}
부분 을 검색하는 코드는 특정 정규식 라이브러리에 따라 다릅니다.
모든 응답에 감사드립니다! 에이스입니다 :)
OneByOne의 답변 (가장 간단 해 보임)을 기반으로 일부 비 캡처 그룹 ( '(? :'부분-비 캡처 그룹을 소개 한 VonC 덕분에!)을 추가 했으므로 캡처 만 수행하는 그룹 숫자 또는 * 문자를 포함합니다.
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$
모두에게 감사합니다!
어떤 플랫폼을 사용하고 있는지 모르지만 .NET에는 "nnnn"버전 번호를 구문 분석하는 System.Version 클래스가 있습니다.
내 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
}
나는 분할 제안에 동의하는 경향이 있습니다.
펄에서 문제에 대한 "테스터"를 만들었습니다.
#!/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
------------------------
이것은 당신이 규정 한대로 작동합니다. 와일드 카드 위치에 따라 달라지며 중첩 된 정규식입니다.
^((\*)|([0-9]+(\.((\*)|([0-9]+(\.((\*)|([0-9]+)))?)))?))$
많은 답변을 봤는데 ... 새로운 답변이 있습니다. 적어도 나를 위해 작동합니다. 새로운 제한을 추가했습니다. 버전 번호는 0이 뒤에 오는 다른 숫자로 시작할 수 없습니다 (주, 부 또는 패치).
01.0.0이 유효하지 않음 1.0.0이 유효 함 10.0.10이 유효 함 1.0.0000이 유효하지 않음
^(?:(0\\.|([1-9]+\\d*)\\.))+(?:(0\\.|([1-9]+\\d*)\\.))+((0|([1-9]+\\d*)))$
이전 버전을 기반으로합니다. 그러나 나는이 해결책을 더 잘 볼 수 있습니다 ... 나를 위해;)
즐겨!!!
또 다른 시도 :
^(((\d+)\.)?(\d+)\.)?(\d+|\*)$
This gives the three parts in groups 4,5,6 BUT: They are aligned to the right. So the first non-null one of 4,5 or 6 gives the version field.
- 1.2.3 gives 1,2,3
- 1.2.* gives 1,2,*
- 1.2 gives null,1,2
- *** gives null,null,*
- 1.* gives null,1,*
^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$
Perhaps a more concise one could be :
^(?:(\d+)\.){0,2}(\*|\d+)$
This can then be enhanced to 1.2.3.4.5.* or restricted exactly to X.Y.Z using * or {2} instead of {0,2}
I had a requirement to search/match for version numbers, that follows maven convention or even just single digit. But no qualifier in any case. It was peculiar, it took me time then I came up with this:
'^[0-9][0-9.]*$'
This makes sure the version,
- Starts with a digit
- Can have any number of digit
- Only digits and '.' are allowed
One drawback is that version can even end with '.' But it can handle indefinite length of version (crazy versioning if you want to call it that)
Matches:
- 1.2.3
- 1.09.5
- 3.4.4.5.7.8.8.
- 23.6.209.234.3
If you are not unhappy with '.' ending, may be you can combine with endswith logic
(?ms)^((?:\d+(?!\.\*)\.)+)(\d+)?(\.\*)?$|^(\d+)\.\*$|^(\*|\d+)$
Does exactly match your 6 first examples, and rejects the 4 others
- group 1: major or major.minor or '*'
- group 2 if exists: minor or *
- group 3 if exists: *
You can remove '(?ms)'
I used it to indicate to this regexp to be applied on multi-lines through QuickRex
This matches 1.2.3.* too
^(*|\d+(.\d+){0,2}(.*)?)$
I would propose the less elegant:
(*|\d+(.\d+)?(.*)?)|\d+.\d+.\d+)
Keep in mind regexp are greedy, so if you are just searching within the version number string and not within a bigger text, use ^ and $ to mark start and end of your string. The regexp from Greg seems to work fine (just gave it a quick try in my editor), but depending on your library/language the first part can still match the "*" within the wrong version numbers. Maybe I am missing something, as I haven't used Regexp for a year or so.
This should make sure you can only find correct version numbers:
^(\*|\d+(\.\d+)*(\.\*)?)$
edit: actually greg added them already and even improved his solution, I am too slow :)
It seems pretty hard to have a regex that does exactly what you want (i.e. accept only the cases that you need and reject all others and return some groups for the three components). I've give it a try and come up with this:
^(\*|(\d+(\.(\d+(\.(\d+|\*))?|\*))?))$
IMO (I've not tested extensively) this should work fine as a validator for the input, but the problem is that this regex doesn't offer a way of retrieving the components. For that you still have to do a split on period.
This solution is not all-in-one, but most times in programming it doesn't need to. Of course this depends on other restrictions that you might have in your code.
Specifying XSD elements:
<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>
My take on this, as a good exercise - vparse, which has a tiny source, with a simple 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;
}
또 하나의 솔루션 :
^[1-9][\d]*(.[1-9][\d]*)*(.\*)?|\*$
참고 URL : https://stackoverflow.com/questions/82064/a-regex-for-version-number-parsing
'developer tip' 카테고리의 다른 글
if-else 또는 다른 비교 연산자를 사용하지 않고 최대 두 개의 정수를 찾는이 스 니펫을 설명 하시겠습니까? (0) | 2020.10.23 |
---|---|
Bash의 배열로 명령 출력 읽기 (0) | 2020.10.23 |
Scala 2.8 컬렉션 디자인 튜토리얼 (0) | 2020.10.23 |
Python 모듈의 절대적 vs. 명시 적 상대적 가져 오기 (0) | 2020.10.23 |
C ++에서 빈 클래스의 크기가 0이 아닌 이유는 무엇입니까? (0) | 2020.10.23 |