The following regex works fine for PCRE, Java and .NET but does no work with Python or Golang. Any clues how to cover those last two would be very much appreciated. Preferable to have one regex to fit them all, but I suspect that two or more will be required.
https://regex101.com/r/E0iVVS/1
^(?<VersionTripple>(?<Major>0|[1-9][0-9]*)\.(?<Minor>0|[1-9][0-9]*)\.(?<Patch>0|[1-9][0-9]*)){1}(?<Tags>(?:\-(?<Prerelease>(?:(?=[0]{1}[0-9A-Za-z-]{0})(?:[0]{1})|(?=[1-9]{1}[0-9]*[A-Za-z]{0})(?:[0-9]+)|(?=[0-9]*[A-Za-z-]+[0-9A-Za-z-]*)(?:[0-9A-Za-z-]+)){1}(?:\.(?=[0]{1}[0-9A-Za-z-]{0})(?:[0]{1})|\.(?=[1-9]{1}[0-9]*[A-Za-z]{0})(?:[0-9]+)|\.(?=[0-9]*[A-Za-z-]+[0-9A-Za-z-]*)(?:[0-9A-Za-z-]+))*){1}){0,1}(?:\+(?<Meta>(?:[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))){0,1})$
Expanded with some comments:
^
(?<VersionTripple>
(?# Version fields are either zero or numeric with no leading zeros.)
(?<Major>0|[1-9][0-9]*)
\.
(?<Minor>0|[1-9][0-9]*)
\.
(?<Patch>0|[1-9][0-9]*)
){1}
(?<Tags>
(?# Either a prerelease tag or a prerelease tag followed by a build meta tag.)
(?:
(?# Prelease tags are preceded by a single dash and have one or more dot seperated identifiers.)
\-
(?<Prerelease>
(?:
(?# Look ahead, is it just zero? Then claim a zero.)
(?=[0]{1}[0-9A-Za-z-]{0})(?:[0]{1})
|
(?# Look ahead, is it pure numeric? Then claim the digits.)
(?=[1-9]{1}[0-9]*[A-Za-z]{0})(?:[0-9]+)
|
(?# Look ahead, is it alphanumeric? Take them all.)
(?=[0-9]*[A-Za-z-]+[0-9A-Za-z-]*)(?:[0-9A-Za-z-]+)
){1}
(?:
(?# Look ahead, is it just zero? Then claim a zero.)
\.(?=[0]{1}[0-9A-Za-z-]{0})(?:[0]{1})
|
(?# Look ahead, is it pure numeric? Then claim the digits.)
\.(?=[1-9]{1}[0-9]*[A-Za-z]{0})(?:[0-9]+)
|
(?# Look ahead, is it alphanumeric? Take them all.)
\.(?=[0-9]*[A-Za-z-]+[0-9A-Za-z-]*)(?:[0-9A-Za-z-]+)
)*
){1}
){0,1}
(?:
(?# Build meta tag is preceded by a plus symbol and followed by one or more dot seperated fields)
\+
(?<Meta>(?:[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))
){0,1}
)
$
Test data:
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
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