breakitdown

Regex for a semantic version (SemVer)

Answer

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.

flags: g all matches · i ignore case · m ^ $ per line · s . matches newlines · u Unicode

JavaScript ✓PCRE ✓

No catastrophic-backtracking patterns found. (A heuristic check: nested and adjacent repeats, overlapping alternatives.)

  1. ^Start of the stringanchor
  2. (…)Capturing group #1: remembers what it matchedgroup
  3. |Either of 2 alternatives, tried left to right; the first that leads to an overall match winsalternation
  4. Alternative 1:
  5. 0The character '0' literallyliteral
  6. Alternative 2:
  7. [1-9]One character: '1' to '9'character class
  8. \dA digit (0-9)character type
  9. *Repeat it zero or more times, as many as possible (greedy)quantifier
  10. \.The character '.' literallyliteral
  11. (…)Capturing group #2: remembers what it matchedgroup
  12. |Either of 2 alternatives, tried left to right; the first that leads to an overall match winsalternation
  13. Alternative 1:
  14. 0The character '0' literallyliteral
  15. Alternative 2:
  16. [1-9]One character: '1' to '9'character class
  17. \dA digit (0-9)character type
  18. *Repeat it zero or more times, as many as possible (greedy)quantifier
  19. \.The character '.' literallyliteral
  20. (…)Capturing group #3: remembers what it matchedgroup
  21. |Either of 2 alternatives, tried left to right; the first that leads to an overall match winsalternation
  22. Alternative 1:
  23. 0The character '0' literallyliteral
  24. Alternative 2:
  25. [1-9]One character: '1' to '9'character class
  26. \dA digit (0-9)character type
  27. *Repeat it zero or more times, as many as possible (greedy)quantifier
  28. (?:…)Non-capturing group: groups without rememberinggroup
  29. -The character '-' literallyliteral
  30. (…)Capturing group #4: remembers what it matchedgroup
  31. [0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class
  32. +Repeat the class one or more times, as many as possible (greedy)quantifier
  33. (?:…)Non-capturing group: groups without rememberinggroup
  34. \.The character '.' literallyliteral
  35. [0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class
  36. +Repeat the class one or more times, as many as possible (greedy)quantifier
  37. *Then repeat the whole group zero or more times, as many as possible (greedy)quantifier
  38. ?Then repeat the whole group optionally (zero or one time)quantifier
  39. (?:…)Non-capturing group: groups without rememberinggroup
  40. \+The character '+' literallyliteral
  41. (…)Capturing group #5: remembers what it matchedgroup
  42. [0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class
  43. +Repeat the class one or more times, as many as possible (greedy)quantifier
  44. (?:…)Non-capturing group: groups without rememberinggroup
  45. \.The character '.' literallyliteral
  46. [0-9A-Za-z-]One character: 0-9 (digits), A-Z (uppercase letters), a-z (lowercase letters) or '-'character class
  47. +Repeat the class one or more times, as many as possible (greedy)quantifier
  48. *Then repeat the whole group zero or more times, as many as possible (greedy)quantifier
  49. ?Then repeat the whole group optionally (zero or one time)quantifier
  50. $End of the stringanchor

5 capturing groups.

Examples

Checked at build time in JavaScript and in Python's re.

InputMatches?
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

Gotchas

Related explainers

← Explain any regular expression