<p>I have a version number of the following form:</p>

<p>version.release.modification</p>

<p>where version, release and modification are either a set of digits or the '*' wildcard character. Additionally, any of these numbers (and any preceding .) may be missing.</p>

<p>So the following are valid and parse as:</p>

<pre><code>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
</code></pre>

<p>But these are not valid:</p>

<pre><code>*.12
*123.1
12*
12.*.34
</code></pre>

<p>Can anyone provide me a not-too-complex regex to validate and retrieve the release, version and modification numbers?</p>

[{'answer_id': 82104, 'author': 'Greg Hewgill', 'author_id': 893, 'author_profile': 'https://Stackoverflow.com/users/893', 'pm_score': 4, 'selected': False, 'text': '<p>This might work:</p>\n\n<pre><code>^(\\*|\\d+(\\.\\d+){0,2}(\\.\\*)?)$\n</code></pre>\n\n<p>At the top level, "*" is a special case of a valid version number. Otherwise, it starts with a number. Then there are zero, one, or two ".nn" sequences, followed by an optional ".*". This regex would accept 1.2.3.* which may or may not be permitted in your application.</p>\n\n<p>The code for retrieving the matched sequences, especially the <code>(\\.\\d+){0,2}</code> part, will depend on your particular regex library.</p>\n'}, {'answer_id': 82152, 'author': 'Paweł Hajdan', 'author_id': 9403, 'author_profile': 'https://Stackoverflow.com/users/9403', 'pm_score': 5, 'selected': False, 'text': '<p><strong>Use regex and now you have two problems.</strong> I would split the thing on dots ("."), then make sure that each part is either a wildcard or set of digits (regex is perfect now). If the thing is valid, you just return correct chunk of the split.</p>\n'}, {'answer_id': 82205, 'author': 'Steve Jessop', 'author_id': 13005, 'author_profile': 'https://Stackoverflow.com/users/13005', 'pm_score': 8, 'selected': True, 'text': '<p>I\'d express the format as:</p>\n\n<blockquote>\n  <p>"1-3 dot-separated components, each numeric except that the last one may be *"</p>\n</blockquote>\n\n<p>As a regexp, that\'s:\n</p>\n\n<pre><code>^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$\n</code></pre>\n\n<p>[Edit to add: this solution is a concise way to validate, but it has been pointed out that extracting the values requires extra work. It\'s a matter of taste whether to deal with this by complicating the regexp, or by processing the matched groups. </p>\n\n<p>In my solution, the groups capture the <code>"."</code> characters. This can be dealt with using non-capturing groups as in ajborley\'s answer.</p>\n\n<p>Also, the rightmost group will capture the last component, even if there are fewer than three components, and so for example a two-component input results in the first and last groups capturing and the middle one undefined. I think this can be dealt with by non-greedy groups where supported.</p>\n\n<p>Perl code to deal with both issues after the regexp could be something like this:</p>\n\n<pre><code>@version = ();\n@groups = ($1, $2, $3);\nforeach (@groups) {\n    next if !defined;\n    s/\\.//;\n    push @version, $_;\n}\n($major, $minor, $mod) = (@version, "*", "*");\n</code></pre>\n\n<p>Which isn\'t really any shorter than splitting on <code>"."</code>\n]</p>\n'}, {'answer_id': 82237, 'author': 'FrankS', 'author_id': 3134, 'author_profile': 'https://Stackoverflow.com/users/3134', 'pm_score': 2, 'selected': False, 'text': '<p>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.\nThe 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.</p>\n\n<p>This should make sure you can only find correct version numbers:</p>\n\n<p>^(\\*|\\d+(\\.\\d+)*(\\.\\*)?)$</p>\n\n<p>edit: actually greg added them already and even improved his solution, I am too slow :)</p>\n'}, {'answer_id': 82262, 'author': 'svrist', 'author_id': 86, 'author_profile': 'https://Stackoverflow.com/users/86', 'pm_score': 3, 'selected': False, 'text': '<p>I tend to agree with split suggestion.</p>\n\n<p>Ive created a "tester" for your problem in perl</p>\n\n<pre><code>#!/usr/bin/perl -w\n\n\n@strings = ( "1.2.3", "1.2.*", "1.*","*" );\n\n%regexp = ( svrist =&gt; qr/(?:(\\d+)\\.(\\d+)\\.(\\d+)|(\\d+)\\.(\\d+)|(\\d+))?(?:\\.\\*)?/,\n            onebyone =&gt; qr/^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$/,\n            greg =&gt; qr/^(\\*|\\d+(\\.\\d+){0,2}(\\.\\*)?)$/,\n            vonc =&gt; qr/^((?:\\d+(?!\\.\\*)\\.)+)(\\d+)?(\\.\\*)?$|^(\\d+)\\.\\*$|^(\\*|\\d+)$/,\n            ajb =&gt; qr/^(?:(\\d+)\\.)?(?:(\\d+)\\.)?(\\*|\\d+)$/,\n            jrudolph =&gt; qr/^(((\\d+)\\.)?(\\d+)\\.)?(\\d+|\\*)$/\n          );\n\n  foreach my $r (keys %regexp){\n    my $reg = $regexp{$r};\n    print "Using $r regexp\\n";\nforeach my $s (@strings){\n  print "$s : ";\n\n    if ($s =~m/$reg/){\n    my ($main, $maj, $min,$rev,$ex1,$ex2,$ex3) = ("any","any","any","any","any","any","any");\n    $main = $1 if ($1 &amp;&amp; $1 ne "*") ;\n    $maj = $2 if ($2 &amp;&amp; $2 ne "*") ;\n    $min = $3 if ($3 &amp;&amp; $3 ne "*") ;\n    $rev = $4 if ($4 &amp;&amp; $4 ne "*") ;\n    $ex1 = $5 if ($5 &amp;&amp; $5 ne "*") ;\n    $ex2 = $6 if ($6 &amp;&amp; $6 ne "*") ;\n    $ex3 = $7 if ($7 &amp;&amp; $7 ne "*") ;\n    print "$main $maj $min $rev $ex1 $ex2 $ex3\\n";\n\n  }else{\n  print " nomatch\\n";\n  }\n  }\nprint "------------------------\\n";\n}\n</code></pre>\n\n<p>Current output:</p>\n\n<pre><code>&gt; perl regex.pl\nUsing onebyone regexp\n1.2.3 : 1. 2. 3 any any any any\n1.2.* : 1. 2. any any any any any\n1.* : 1. any any any any any any\n* : any any any any any any any\n------------------------\nUsing svrist regexp\n1.2.3 : 1 2 3 any any any any\n1.2.* : any any any 1 2 any any\n1.* : any any any any any 1 any\n* : any any any any any any any\n------------------------\nUsing vonc regexp\n1.2.3 : 1.2. 3 any any any any any\n1.2.* : 1. 2 .* any any any any\n1.* : any any any 1 any any any\n* : any any any any any any any\n------------------------\nUsing ajb regexp\n1.2.3 : 1 2 3 any any any any\n1.2.* : 1 2 any any any any any\n1.* : 1 any any any any any any\n* : any any any any any any any\n------------------------\nUsing jrudolph regexp\n1.2.3 : 1.2. 1. 1 2 3 any any\n1.2.* : 1.2. 1. 1 2 any any any\n1.* : 1. any any 1 any any any\n* : any any any any any any any\n------------------------\nUsing greg regexp\n1.2.3 : 1.2.3 .3 any any any any any\n1.2.* : 1.2.* .2 .* any any any any\n1.* : 1.* any .* any any any any\n* : any any any any any any any\n------------------------\n</code></pre>\n'}, {'answer_id': 82271, 'author': 'VonC', 'author_id': 6309, 'author_profile': 'https://Stackoverflow.com/users/6309', 'pm_score': 2, 'selected': False, 'text': '<pre><code>(?ms)^((?:\\d+(?!\\.\\*)\\.)+)(\\d+)?(\\.\\*)?$|^(\\d+)\\.\\*$|^(\\*|\\d+)$\n</code></pre>\n\n<p>Does exactly match your 6 first examples, and rejects the 4 others</p>\n\n<ul>\n<li>group 1: major or major.minor or \'*\'</li>\n<li>group 2 if exists: minor or *</li>\n<li>group 3 if exists: *</li>\n</ul>\n\n<p>You can remove \'(?ms)\'<br>\nI used it to indicate to this regexp to be applied on multi-lines through <a href="http://bastian-bergerhoff.com/eclipse/features/web/QuickREx/toc.html" rel="nofollow noreferrer">QuickRex</a></p>\n'}, {'answer_id': 82296, 'author': 'Duncan Smart', 'author_id': 1278, 'author_profile': 'https://Stackoverflow.com/users/1278', 'pm_score': 3, 'selected': False, 'text': '<p>Don\'t know what platform you\'re on but in .NET there\'s the System.Version class that will parse "n.n.n.n" version numbers for you.</p>\n'}, {'answer_id': 82328, 'author': 'Victor', 'author_id': 14514, 'author_profile': 'https://Stackoverflow.com/users/14514', 'pm_score': 2, 'selected': False, 'text': '<p>This matches 1.2.3.* too</p>\n\n<blockquote>\n  <p>^(*|\\d+(.\\d+){0,2}(.*)?)$</p>\n</blockquote>\n\n<p>I would propose the less elegant:</p>\n\n<p>(*|\\d+(.\\d+)?(.*)?)|\\d+.\\d+.\\d+)</p>\n'}, {'answer_id': 82427, 'author': 'Andrew Borley', 'author_id': 7271, 'author_profile': 'https://Stackoverflow.com/users/7271', 'pm_score': 4, 'selected': False, 'text': "<p>Thanks for all the responses! This is ace :)</p>\n\n<p>Based on OneByOne's answer (which looked the simplest to me), I added some non-capturing groups (the '(?:' parts - thanks to VonC for introducing me to non-capturing groups!), so the groups that do capture only contain the digits or * character. </p>\n\n<pre><code>^(?:(\\d+)\\.)?(?:(\\d+)\\.)?(\\*|\\d+)$\n</code></pre>\n\n<p>Many thanks everyone!</p>\n"}, {'answer_id': 82472, 'author': 'jrudolph', 'author_id': 7647, 'author_profile': 'https://Stackoverflow.com/users/7647', 'pm_score': 2, 'selected': False, 'text': '<p>Another try:</p>\n\n<pre><code>^(((\\d+)\\.)?(\\d+)\\.)?(\\d+|\\*)$\n</code></pre>\n\n<p>This gives the three parts in groups 4,5,6 BUT:\nThey are aligned to the right. So the first non-null one of 4,5 or 6 gives the version field.</p>\n\n<ul>\n<li>1.2.3 gives 1,2,3</li>\n<li>1.2.* gives 1,2,*</li>\n<li>1.2 gives null,1,2</li>\n<li>*** gives null,null,*</li>\n<li>1.* gives null,1,*</li>\n</ul>\n'}, {'answer_id': 82488, 'author': 'rslite', 'author_id': 15682, 'author_profile': 'https://Stackoverflow.com/users/15682', 'pm_score': 2, 'selected': False, 'text': "<p>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 <strong>all</strong> others <em>and</em> return some groups for the three components). I've give it a try and come up with this:</p>\n\n<pre><code>^(\\*|(\\d+(\\.(\\d+(\\.(\\d+|\\*))?|\\*))?))$\n</code></pre>\n\n<p>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.</p>\n\n<p>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.</p>\n"}, {'answer_id': 82598, 'author': 'ofaurax', 'author_id': 15209, 'author_profile': 'https://Stackoverflow.com/users/15209', 'pm_score': 3, 'selected': False, 'text': '<pre><code>^(?:(\\d+)\\.)?(?:(\\d+)\\.)?(\\*|\\d+)$\n</code></pre>\n\n<p>Perhaps a more concise one could be :</p>\n\n<pre><code>^(?:(\\d+)\\.){0,2}(\\*|\\d+)$\n</code></pre>\n\n<p>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}</p>\n'}, {'answer_id': 2619727, 'author': 'nomuus', 'author_id': 314179, 'author_profile': 'https://Stackoverflow.com/users/314179', 'pm_score': 3, 'selected': False, 'text': '<p>This should work for what you stipulated.  It hinges on the wild card position and is a nested regex:</p>\n\n<pre><code>^((\\*)|([0-9]+(\\.((\\*)|([0-9]+(\\.((\\*)|([0-9]+)))?)))?))$\n</code></pre>\n\n<p><img src="https://i.stack.imgur.com/wAazA.png" alt="http://imgur.com/3E492.png"></p>\n'}, {'answer_id': 16540907, 'author': 'Israel Romero', 'author_id': 1485676, 'author_profile': 'https://Stackoverflow.com/users/1485676', 'pm_score': 3, 'selected': False, 'text': "<p>I've seen a lot of answers, but... i have a new one. It works for me at least. I've added a new restriction. Version numbers can't start (major, minor or patch) with any zeros followed by others.</p>\n\n<blockquote>\n  <p>01.0.0   is not valid\n  1.0.0    is valid\n  10.0.10  is valid \n  1.0.0000 is not valid</p>\n</blockquote>\n\n<pre><code>^(?:(0\\\\.|([1-9]+\\\\d*)\\\\.))+(?:(0\\\\.|([1-9]+\\\\d*)\\\\.))+((0|([1-9]+\\\\d*)))$\n</code></pre>\n\n<p>It's based in a previous one. But i see this solution better... for me ;)</p>\n\n<p>Enjoy!!!</p>\n"}, {'answer_id': 27540795, 'author': 'Sudhanshu Mishra', 'author_id': 190476, 'author_profile': 'https://Stackoverflow.com/users/190476', 'pm_score': 4, 'selected': False, 'text': '<p>My 2 cents: I had this scenario: I had to parse version numbers out of a string literal.\n(I know this is very different from the original question, but googling to find a regex for parsing version number showed this thread at the top, so adding this answer here)</p>\n\n<p>So the string literal would be something like: "Service version 1.2.35.564 is running!"</p>\n\n<p>I had to parse the 1.2.35.564 out of this literal. Taking a cue from @ajborley, my regex is as follows:</p>\n\n<pre><code>(?:(\\d+)\\.)?(?:(\\d+)\\.)?(?:(\\d+)\\.\\d+)\n</code></pre>\n\n<p>A small C# snippet to test this looks like below:</p>\n\n<pre><code>void Main()\n{\n    Regex regEx = new Regex(@"(?:(\\d+)\\.)?(?:(\\d+)\\.)?(?:(\\d+)\\.\\d+)", RegexOptions.Compiled);\n\n    Match version = regEx.Match("The Service SuperService 2.1.309.0) is Running!");\n    version.Value.Dump("Version using RegEx");   // Prints 2.1.309.0        \n}\n</code></pre>\n'}, {'answer_id': 39345000, 'author': 'Oleksandr Yarushevskyi', 'author_id': 4262975, 'author_profile': 'https://Stackoverflow.com/users/4262975', 'pm_score': 2, 'selected': False, 'text': '<p>One more solution:</p>\n\n<pre><code>^[1-9][\\d]*(.[1-9][\\d]*)*(.\\*)?|\\*$\n</code></pre>\n'}, {'answer_id': 41364868, 'author': 'Emmerson', 'author_id': 3159257, 'author_profile': 'https://Stackoverflow.com/users/3159257', 'pm_score': 2, 'selected': False, 'text': '<p>Specifying XSD elements:</p>\n\n<pre><code>&lt;xs:simpleType&gt;\n    &lt;xs:restriction base="xs:string"&gt;\n        &lt;xs:pattern value="[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}(\\..*)?"/&gt;\n    &lt;/xs:restriction&gt;\n&lt;/xs:simpleType&gt;\n</code></pre>\n'}, {'answer_id': 44088487, 'author': 'vitaly-t', 'author_id': 1102051, 'author_profile': 'https://Stackoverflow.com/users/1102051', 'pm_score': 2, 'selected': False, 'text': '<p>My take on this, as a good exercise - <a href="https://github.com/vitaly-t/vparse" rel="nofollow noreferrer">vparse</a>, which has a <a href="https://github.com/vitaly-t/vparse/blob/master/index.js" rel="nofollow noreferrer">tiny source</a>, with a simple function:</p>\n\n<pre><code>function parseVersion(v) {\n    var m = v.match(/\\d*\\.|\\d+/g) || [];\n    v = {\n        major: +m[0] || 0,\n        minor: +m[1] || 0,\n        patch: +m[2] || 0,\n        build: +m[3] || 0\n    };\n    v.isEmpty = !v.major &amp;&amp; !v.minor &amp;&amp; !v.patch &amp;&amp; !v.build;\n    v.parsed = [v.major, v.minor, v.patch, v.build];\n    v.text = v.parsed.join(\'.\');\n    return v;\n}\n</code></pre>\n'}, {'answer_id': 44500980, 'author': 'Shiva', 'author_id': 2068802, 'author_profile': 'https://Stackoverflow.com/users/2068802', 'pm_score': 3, 'selected': False, 'text': "<p>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:</p>\n\n<pre><code>'^[0-9][0-9.]*$'\n</code></pre>\n\n<p>This makes sure the version,</p>\n\n<ol>\n<li>Starts with a digit</li>\n<li>Can have any number of digit</li>\n<li>Only digits and '.' are allowed</li>\n</ol>\n\n<p>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)</p>\n\n<p>Matches:</p>\n\n<ul>\n<li>1.2.3</li>\n<li>1.09.5</li>\n<li>3.4.4.5.7.8.8.</li>\n<li>23.6.209.234.3</li>\n</ul>\n\n<p>If you are not unhappy with '.' ending, may be you can combine with endswith logic</p>\n"}, {'answer_id': 62344454, 'author': 'Pau Ballada', 'author_id': 1542507, 'author_profile': 'https://Stackoverflow.com/users/1542507', 'pm_score': 3, 'selected': False, 'text': '<p>For parsing version numbers that follow these rules:\n - Are only digits and dots\n - Cannot start or end with a dot\n - Cannot be two dots together</p>\n\n<p>This one did the trick to me.</p>\n\n<pre><code>^(\\d+)((\\.{1}\\d+)*)(\\.{0})$\n</code></pre>\n\n<p>Valid cases are:</p>\n\n<p>1, 0.1, 1.2.1</p>\n'}, {'answer_id': 64274924, 'author': 'Marc Ruef', 'author_id': 6424520, 'author_profile': 'https://Stackoverflow.com/users/6424520', 'pm_score': 2, 'selected': False, 'text': '<p>Sometimes version numbers might contain alphanumeric minor information (e.g. <em>1.2.0b</em> or <em>1.2.0-beta</em>). In this case I am using this regex:</p>\n<pre><code>([0-9]{1,4}(\\.[0-9a-z]{1,6}){1,5})\n</code></pre>\n'}, {'answer_id': 64784354, 'author': 'Or Assayag', 'author_id': 4442606, 'author_profile': 'https://Stackoverflow.com/users/4442606', 'pm_score': 1, 'selected': False, 'text': '<p>I found this, and it works for me:</p>\n<pre><code>/(\\^|\\~?)(\\d|x|\\*)+\\.(\\d|x|\\*)+\\.(\\d|x|\\*)+\n</code></pre>\n'}, {'answer_id': 70575435, 'author': '山茶树和葡萄树', 'author_id': 5819157, 'author_profile': 'https://Stackoverflow.com/users/5819157', 'pm_score': 1, 'selected': False, 'text': '<pre><code>/^([1-9]{1}\\d{0,3})(\\.)([0-9]|[1-9]\\d{1,3})(\\.)([0-9]|[1-9]\\d{1,3})(\\-(alpha|beta|rc|HP|CP|SP|hp|cp|sp)[1-9]\\d*)?(\\.C[0-9a-zA-Z]+(-U[1-9]\\d*)?)?(\\.[0-9a-zA-Z]+)?$/\n</code></pre>\n<ul>\n<li>A normal version: <code>([1-9]{1}\\d{0,3})(\\.)([0-9]|[1-9]\\d{1,3})(\\.)([0-9]|[1-9]\\d{1,3})</code></li>\n<li>A Pre-release or patched version: <code>(\\-(alpha|beta|rc|EP|HP|CP|SP|ep|hp|cp|sp)[1-9]\\d*)?</code>  (Extension Pack, Hotfix Pack, Coolfix Pack, Service Pack)</li>\n<li>Customized version: <code>(\\.C[0-9a-zA-Z]+(-U[1-9]\\d*)?)?</code></li>\n<li>Internal version: <code>(\\.[0-9a-zA-Z]+)?</code></li>\n</ul>\n<p><a href="https://i.stack.imgur.com/Qnquk.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Qnquk.png" alt="enter image description here" /></a></p>\n'}]
['https://Stackoverflow.com/questions/82064', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/7271/']