mirror of
https://github.com/semver/semver.git
synced 2026-07-11 05:12:48 -05:00
RegEx for validating SemVer-numbers #158
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @DavidFichtmueller on GitHub (Nov 13, 2014).
I just created a RegEx to check if a version number is a valid Semantic Version Number according to the specification.
Maybe this is useful for some people out there or it could be added to the documentation.
@sorki commented on GitHub (Dec 11, 2014):
+1 for adding to docs. Exactly what is was looking for. Thank you!
@ghost commented on GitHub (Feb 27, 2015):
Would be nice to have this in the official SemVer specification !
@BartG95 commented on GitHub (Aug 26, 2015):
If I'm not mistaken
is the same as
(note the plus)
@quantumpacket commented on GitHub (Aug 26, 2015):
No, the first one requires that there be at least one character from the range
[a-zA-Z- ]since it has no wildcard. However, the second one does not require at least one char from that range. The string12345fails the first, while it passes the second.@BartG95 commented on GitHub (Aug 27, 2015):
Right, but it is part of
So "12345" wil pass anyway.
Edit: if it is changed as in my previous comment, leading zero's will pass. I'm sorry ;)
@chepner commented on GitHub (Aug 25, 2017):
If this isn't part of an actual implementation, it should use only (POSIX) standard features, like
[[:digit:]]in place of\d.@silkentrance commented on GitHub (Nov 22, 2017):
Perhaps you should get into touch with gulp-bump and ask them for using the to be established official regex:
f705057087/index.js (L28)and export that regex for reuse purposes, e.g. scanning through files and replacing occurrences within these files.
@silkentrance commented on GitHub (Nov 22, 2017):
There is also https://github.com/sindresorhus/semver-regex, perhaps you want to join efforts here.
@silkentrance commented on GitHub (Nov 22, 2017):
And there is also https://github.com/semver/semver.org/issues/59. Get your gears straight.
@jwdonahue commented on GitHub (Nov 30, 2017):
@DavidFichtmueller, near as I can tell, if you want it included in or linked from the semver.org site, you really should contribute to semver/semver.org#59.
Please close this issue at your earliest possible convenience.
@jwdonahue commented on GitHub (Jul 15, 2018):
@DavidFichtmueller, I just ran your regex against the test data set we've been using over on semver/semver.org#59 and it correctly matches all the positive examples while rejecting all of the negative examples, including one particularly degenerate version string that causes excessive back-tracking in many of the proposed regex's. If you could add named capture groups, this would be awesome.
@gvlx commented on GitHub (Jul 17, 2018):
Hi @DavidFichtmueller ,
I just made a comparision of your definition against mine.
Your case achieves the full test case in 2345 steps which is more than twice as fast as mine - 5015 steps! :)
Besides reducing the number of groups to the minimum (which has to be verified for all the implementations - some could require some extra groups) and substituting
/[0-9]/by/\d/(which not all implementations accept), you achieved a greater simplification goingfrom
/[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*/to/\d*[a-zA-Z-][0-9a-zA-Z-]*/.@gvlx commented on GitHub (Jul 17, 2018):
Adding named groups and non-capturing groups decreases performance to 2501 steps.
See it here.
@DavidFichtmueller commented on GitHub (Jul 17, 2018):
@gvlx thanks for the comparison, that is really interesting.
Also you were quicker than me, creating the version with the named groups (I also added the non-capturing groups and pretty much got the same result as you with the 2501 steps).
@jwdonahue here is the version as requested with the named groups:
^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$and here without the named groups (for the systems that don't support it yet), but with the non capturing groups (so cg1 = major, cg2 = minor, cg3 = patch, cg4 = prerelease and cg5 = buildmetadata):
^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$@jwdonahue commented on GitHub (Aug 8, 2018):
@DavidFichtmueller, do you have time to issue a pull request? I am thinking we should add an "Is there an efficient regex?" to the FAQ and include those in the answer. If you don't have time, I might get to it this week-end.
@fourpastmidnight commented on GitHub (Oct 17, 2018):
All of these Regular expressions don't parse the version string strictly according to the SemVer spec. The Regular expressions shown thus far in this issue allows for the following invalid version strings:
These are invalid because the version numbers
0.0.0and0.0.1are invalid. The minimum version number allowed by the spec is0.1.0.I had developed my own Regex a while back, and the RegEx @DavidFichtmueller wrote above was very close to what I had. My Regular Expression introduces a Zero-Width Positive Look-Behind group in the
(?<Minor>)portion of the regular expression. This may make the RegEx more inefficient, but it depends on what your goal is: speed vs. correctness. Here's that part, shown with extra spacing to help things stand out:This says "Match a
0if the0is preceded with a digit 1-9 followed by zero or more digits followed by a period, otherwise match a digit 1-9 followed by zero or more digits".In addition, I added the
(?n)to the beginning of the regular expression so that only named capture groups are captured so that I don't have to use(?: ... )for non-captured groups. Finally, I also provided two extra named capture groups to enable you to capture the Pre-release and Build-metadata tags with and without the leading-and+(respectively)--but those extra captures can be easily be removed.Here's a copy/paste friendly version of the regular expression in its entirety:
And here's the one-liner version:
@gvlx commented on GitHub (Oct 17, 2018):
Hi,
I went back to read the specification and couldn't find the constraint on using a
0.0.0version.Are you sure of this?
@jwdonahue commented on GitHub (Oct 17, 2018):
@fourpastmidnight said:
Incorrect. See #4 in the spec. The relevant FAQ suggests that starting at 0.1.0 is a good idea, but it's not required. It's a common practice to shift the semantic meaning of the fields one to the right for the 0.y.z series versions such that a bump of the minor field is a breaking change bumps in the patch version can be bug fixes and new features.
Your regex fails to validate the compliant version string 0.0.4. Here's the [so far] agreed test set:
0.0.4
1.2.3
10.20.30
1.1.2-prerelease+meta
1.1.2+meta
1.1.2+meta-valid
1.0.0-alpha
1.0.0-beta
1.0.0-alpha.beta
1.0.0-alpha.beta.1
1.0.0-alpha.1
1.0.0-alpha0.valid
1.0.0-alpha.0valid
1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay
1.0.0-rc.1+build.1
2.0.0-rc.1+build.123
1.2.3-beta
10.2.3-DEV-SNAPSHOT
1.2.3-SNAPSHOT-123
1.0.0
2.0.0
1.1.7
2.0.0+build.1848
2.0.1-alpha.1227
1.0.0-alpha+beta
1.2.3----RC-SNAPSHOT.12.9.1--.12+788
1.2.3----R-S.12.9.1--.12+meta
1.2.3----RC-SNAPSHOT.12.9.1--.12
1.0.0+0.build.1-rc.10000aaa-kk-0.1
99999999999999999999999.999999999999999999.99999999999999999
1.0.0-0A.is.legal
Begin Invalid
1
1.2
1.2.3-0123
1.2.3-0123.0123
1.1.2+.123
+invalid
-invalid
-invalid+invalid
-invalid.01
alpha
alpha.beta
alpha.beta.1
alpha.1
alpha+beta
alpha_beta
alpha.
alpha..
beta
1.0.0-alpha_beta
-alpha.
1.0.0-alpha..
1.0.0-alpha..1
1.0.0-alpha...1
1.0.0-alpha....1
1.0.0-alpha.....1
1.0.0-alpha......1
1.0.0-alpha.......1
01.1.1
1.01.1
1.1.01
1.2
1.2.3.DEV
1.2-SNAPSHOT
1.2.31.2.3----RC-SNAPSHOT.12.09.1--..12+788
1.2-RC-SNAPSHOT
-1.0.3-gamma+b7718
+justmeta
9.8.7+meta+meta
9.8.7-whatever+meta+meta
99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12
@jwdonahue commented on GitHub (Oct 17, 2018):
@fourpastmidnight, I do like that your regex is fairly short and seems to be performant. I think the 0.0.0 version should be added to the top of the test data. It's valid, allows for initializing version objects and frankly, indicates the interface doesn't exist or the developer isn't sure yet whether there will be any "API".
@fourpastmidnight commented on GitHub (Oct 17, 2018):
You’re right! I totally inferred that rule from the suggestion in the FAQ, but section 4 specifies no such constraint. In which case, the regexes supplied here, especially the one from @DavidFichtmueller, are correct. My apologies.
Sent from my Windows 10 phone
From: Gerardo Lisboa
Sent: Wednesday, October 17, 2018 18:31
To: semver/semver
Cc: Craig E. Shea; Comment
Subject: Re: [semver/semver] RegEx for validating SemVer-numbers (#232)
Hi,
I went back to read the specification and couldn't find the constraint on using a 0.0.0 version.
Are you sure of this?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
@fourpastmidnight commented on GitHub (Oct 18, 2018):
The only thing that was needed to pass the test concerning the regular expressions above is to remove the Zero-Width Positive Look-Behind group in the
(?<Minor> ...)component of my Regex that I added due to inferring a non-existent constraint based on a suggestion in the FAQ 😉.So, here's my corrected RegEx, which, aside from the difference in captured group capitalization and captured groups that both include and exclude the leading
-and+of the pre-release and build metadata tags, is otherwise the same as @DavidFichtmueller's. So, great job by him!And again, the one-liner:
Thanks for pointing out my incorrect assertion @gvlx and @jwdonahue.
As an aside, I found my way here because I was testing a PowerShell function I wrote a few years back that parses a "version string". My original RegEx, in addition to handling SemVer compliant strings, also loosely supports parsing NuGet Legacy style version strings. The only good thing about all of this is, because I independently came up with the same solution as DavidFichtmueller, we can be pretty darn sure it works correctly (when the spec is actually followed 😉 lol). The script I wrote returns a
PSCustomObjectto represent the version data and you can inspect the individual components and get string representations of it in SemVer 2.0 or NuGet legacy formats. I even have a comparison script that can compare two versions and return -1, 0, or 1 to indicate whether one version is less than, equal to, or greater than another. I'll end up posting those to my GitHub account in a few days, most likely. I hadn't needed them again until recently and decided to write tests for them, which is what brought me here today. I'm still trying to wrap up the last of the unit tests.@jwdonahue commented on GitHub (Oct 18, 2018):
@fourpastmidnight, thank you for your efforts, I look forward to ripping your powershell scripts ;).
If you happen upon any interesting positive/negative oracles to test against, please add them to our list and post them here. I will eventually issue a PR to get them checked-in.
@lkmorlan commented on GitHub (Apr 1, 2019):
This allows build metadata to end with a period. To prevent this, change one
*to+:@fourpastmidnight commented on GitHub (Apr 1, 2019):
Good catch! Thanks.
Sent from my Windows 10 phone
From: Liam Morland
Sent: Monday, April 1, 2019 11:08
To: semver/semver
Cc: Craig E. Shea; Mention
Subject: Re: [semver/semver] RegEx for validating SemVer-numbers (#232)
+(?[\dA-Za-z-]+(.[\dA-Za-z-]))
This allows build metadata to end with a period. To prevent this, change one * to +:
+(?[\dA-Za-z-]+(.[\dA-Za-z-]+)*)
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
@gvlx commented on GitHub (Apr 2, 2019):
Hi @fourpastmidnight, please check your
PreReleaseTag, I have the impression you are having the same issue as with theBuildMetadataTag.@SupinePandora43 commented on GitHub (Jun 12, 2019):
RegEX for validating alpha/beta
based on
@jwdonahue commented on GitHub (Aug 10, 2019):
It seems that PR #460 has been completed. We now have a pair of well vetted pair of regex's included in the spec.
Can we please close this discussion now?
@DavidFichtmueller commented on GitHub (Aug 12, 2019):
@jwdonahue yes, you are right. This can be closed now.
@fourpastmidnight commented on GitHub (Oct 26, 2019):
Sorry for the very late reply. I did check into this and there doesn't appear to be the same issue with the pre-release tag portion of my SemVer regex:
@jwdonahue commented on GitHub (Oct 26, 2019):
@fourpastmidnight, you cannot have empty identifiers in the prerelease and meta tags. In other words, the trailing dot on your "-alpha1." is not legal because it creates an empty identifier.
@fourpastmidnight commented on GitHub (Oct 26, 2019):
Hm, well, I found another error too, while validating my regex—a prerelease tag of
-00was considered valid but it’s not valid according to the spec. So, I made some changes to the tags portion that align with the BNF grammar and now everything works. I’ll post my updated regex later tonight, just because—and finally look to post that set of PowerShell scripts I talked about a year ago!Sent from my Windows 10 phone
From: Joseph Donahue
Sent: Saturday, October 26, 2019 14:59
To: semver/semver
Cc: Craig E. Shea; Mention
Subject: Re: [semver/semver] RegEx for validating SemVer-numbers (#232)
@fourpastmidnight, you cannot have empty identifiers in the prerelease and meta tags. In other words, the trailing dot on your "-alpha1." is not legal because it creates an empty identifier.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.
@fourpastmidnight commented on GitHub (Oct 27, 2019):
@jwdonahue:
Oh, I see now, you were a bit confused by my previous post. The post was showing that my earlier regex did indeed NOT match
-alpah1.as shown by theFalseoutput from$semver.IsMatch('1.0.0-alpha1.).In any event, as stated above, I did find that my regex did allow for an invalid pre-release tag containing leading zeros. But thanks to the very well written BNF notation in the spec, I have been able to resolve that issue and along the way refine the regex a bit more.
I'll post it here later with timing results from Regex101.com.
@fourpastmidnight commented on GitHub (Oct 27, 2019):
OK, so here's my new, corrected, and improved Regex for parsing/validating SemVer 2.0 version strings. It is up to 24% faster than the regex's listed on the homepage of SemVer.org.
In addition, when validating the below Regex with the above list of valid/invalid SemVer versions, one of the invalid Build Metadata version regexes was also listed as valid during my initial remediation efforts (again due to using
\d*instead of\d+--you'd think I've learned by now 😉 ):1.1.2+.123. I then realized that the list above does not contain a similar invalid pre-release tag:1.1.2-.123. Luckily, that one was flagged as invalid. Additionally, I found another missing invalid case:1.1.2+0.; and during my remediation efforts, this was also matching (again due to a\d*instead of\d+). I've added this to the list of Invalid SemVer version strings.The Regex below matches the entire list, 31 matches, in 2058 steps which is 460 steps (+18.27%) faster than the Regex at the SemVer.org homepage. (Note that for Regex101, the .NET
(?n)modifier is not supported and you need to replace all unnamed capture groups with(?>...)to "exclude" them from capture to achieve the best performance. The regex shown below is the .NET version. Follow the link to Regex101 for a PCRE version.)And here's the one-liner:
If you don't need the capture groups (i.e. you're only interested in validating a SemVer version string or capturing the entire string without needing the breakdown of the various parts of the string), then you can use this better performing version of the Regex which performs all the matches in 1905 steps, which is 613 steps (+24.34%) faster than the non-capturing regex on the SemVer.org homepage (which, oddly enough, has the same number of steps as the capturing one)--again, this is the .NET version:
And once again, the one-liner:
I recently came back to this because I was creating a cmdlet for adding a Channel Version Rule to an Octopus Deploy deployment process resource. Anyway, hopefully, I can post my PowerShell scripts soon, along with attendant tests.
@sheeeng commented on GitHub (Nov 13, 2020):
How about a numeric only regular expression based on the official suggestion? For example,
1.2.3should match, but both1.2.3-rc1and1.2.3-alpha1should not match.I am using the following numeric only regular expression.
Please correct me if I misunderstood the expressions.
@slayer321 commented on GitHub (Nov 11, 2022):
The above regex mention by @DavidFichtmueller failed for this condition
you can use the below regex
@DavidFichtmueller commented on GitHub (Nov 11, 2022):
@slayer321 : can you please specify which of the regexes mentioned by me, fails for this case? I double checked them and it worked for all (the regex itself has evolved over the course of this discussion). But most importantly, it works for the two expressions mentioned on the website: https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string (use the two regex101.com-links for the test environment with the expected test cases, you can add "0.10.1" to it, to double check it).