Regex for a semantic version (SemVer)
This pattern matches MAJOR.MINOR.PATCH with no leading zeros, an optional -prerelease and an optional +build, each made of dot-separated alphanumeric identifiers. Groups 1-5 capture major, minor, patch, pre-release and build metadata. semver.org publishes a longer official regex that is stricter about pre-release numbers.
JavaScript ✓PCRE ✓
No catastrophic-backtracking patterns found. (A heuristic check: nested and adjacent repeats, overlapping alternatives.)
^Start of the stringanchor(…)Capturing group #1: remembers what it matchedgroup|Either of 2 alternatives, tried left to right; the first that leads to an overall match winsalternation- Alternative 1:
0The character '0' literallyliteral- Alternative 2:
[1-9]One character: '1' to '9'character class\dA digit (0-9)character type*Repeat it zero or more times, as many as possible (greedy)quantifier\.The character '.' literallyliteral(…)Capturing group #2: remembers what it matchedgroup|Either of 2 alternatives, tried left to right; the first that leads to an overall match winsalternation- Alternative 1:
0The character '0' literallyliteral- Alternative 2:
[1-9]One character: '1' to '9'character class\dA digit (0-9)character type*Repeat it zero or more times, as many as possible (greedy)quantifier\.The character '.' literallyliteral(…)Capturing group #3: remembers what it matchedgroup|Either of 2 alternatives, tried left to right; the first that leads to an overall match winsalternation- Alternative 1:
0The character '0' literallyliteral- Alternative 2:
[1-9]One character: '1' to '9'character class\dA digit (0-9)character type*Repeat it zero or more times, as many as possible (greedy)quantifier(?:…)Non-capturing group: groups without rememberinggroup-The character '-' literallyliteral(…)Capturing group #4: remembers what it matchedgroup[0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class+Repeat the class one or more times, as many as possible (greedy)quantifier(?:…)Non-capturing group: groups without rememberinggroup\.The character '.' literallyliteral[0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class+Repeat the class one or more times, as many as possible (greedy)quantifier*Then repeat the whole group zero or more times, as many as possible (greedy)quantifier?Then repeat the whole group optionally (zero or one time)quantifier(?:…)Non-capturing group: groups without rememberinggroup\+The character '+' literallyliteral(…)Capturing group #5: remembers what it matchedgroup[0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class+Repeat the class one or more times, as many as possible (greedy)quantifier(?:…)Non-capturing group: groups without rememberinggroup\.The character '.' literallyliteral[0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class+Repeat the class one or more times, as many as possible (greedy)quantifier*Then repeat the whole group zero or more times, as many as possible (greedy)quantifier?Then repeat the whole group optionally (zero or one time)quantifier$End of the stringanchor
5 capturing groups.
Examples
Checked at build time in JavaScript and in Python's re.
| Input | Matches? |
|---|---|
1.2.3 | ✓ match |
0.0.0 | ✓ match |
1.0.0-alpha.1 | ✓ match |
1.0.0+build.5 | ✓ match |
1.0.0-rc.1+sha.5114f85 | ✓ match |
v1.2.3 | ✗ no match |
1.2 | ✗ no match |
01.2.3 | ✗ no match |
1.0.0- | ✗ no match |
1.0.0-01 | ✓ match |
Try your own text
One string per line: each line is tested on its own (the m flag is added here).
How it works
Each version number is 0|[1-9]\d*: either zero or a number that does not start with zero. SemVer 2.0.0 forbids leading zeros, so 01.2.3 fails. Pre-release and build parts are identifiers of letters, digits and hyphens, separated by dots.
The one rule this simplified version skips: numeric pre-release identifiers must not have leading zeros either. 1.0.0-01 is invalid SemVer but passes here. The official regex (in the variants) handles that with an extra alternation. If you need to sort versions, not just validate them, use a library such as the semver package on npm. Precedence rules (for example, 1.0.0-alpha < 1.0.0) are not something a regex can express.
Variants
/^(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-]+)*))?$/The official regex from semver.org. Rejects leading zeros in numeric pre-release identifiers./^v?(\d+)\.(\d+)\.(\d+)/Loose: pull the three numbers out of a tag likev2.10.4-rc1.
Gotchas
- A leading
vfails. Git tags often usev1.2.3, but the spec says thevis not part of the version. Strip it first or allow^v?. 1.0.0-01passes this pattern but is invalid SemVer. Use the official regex if you publish to a registry that enforces the spec.- npm ranges like
^1.2.0or~1.2are not versions. They need a range parser.
Related explainers
- Regex for digits only, integers and decimalsRegexes for digits only, signed integers and decimal numbers, with the edge cases: leading zeros, a bare...
- Regex for a YYYY-MM-DD dateA regex for ISO 8601 calendar dates (YYYY-MM-DD) with month and day ranges, and why you still have to...
- Regex for a UUIDRegexes for UUIDs in the standard 8-4-4-4-12 form: any version, version 4 only, and versions 1-8 with the...