0

Please help me to write regex to parse the following string

{0}:{1}:{2}

where {0} is GUID, {1} and {2} is a number in range from 1 to 65536

Examples:

123e4567-e89b-12d3-a456-9AC7CBDCEE52:21:4552
7e21dc49-8640-4982-b3eb-51608b680e3c:1:65536
982e1b18-ac35-4eba-84fc-53bc1c993dcf:6441:4

Note: GUID should be without braces (only 36 symbols length).

This is what I have tried

(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}(:\d+:\d+|$)$

but it's allow any numbers. Could you please help? Is there shorter way to

Я TChebur
  • 366
  • 6
  • 23

2 Answers2

3

Regex are a cumbersome way to validate that numbers lie within a range, but it is possible. I'd recommend validating the numeric values in some other way if possible. If you must use regex, here's the basic concept for validating a numeric range:

Since regular expressions deal with text rather than with numbers, matching a number in a given range takes a little extra care. You can’t just write [0-255] to match a number between 0 and 255. Though a valid regex, it matches something entirely different. [0-255] is a character class with three elements: the character range 0-2, the character 5 and the character 5 (again). This character class matches a single digit 0, 1, 2 or 5, just like [0125].

Matching the three-digit numbers is a little more complicated, since we need to exclude numbers 256 through 999. 1[0-9][0-9] takes care of 100 to 199. 2[0-4][0-9] matches 200 through 249. Finally, 25[0-5] adds 250 till 255.

Putting this all together using alternation we get: [0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]. This matches the numbers we want, with one caveat: regular expression searches usually allow partial matches, so our regex would match 123 in 12345. There are two solutions to this.

(full text at https://www.regular-expressions.info/numericranges.html)

I'm lazy, so instead of building a huge regex to match 1-65536 by hand I used http://gamon.webfactional.com/regexnumericrangegenerator/. The result:

([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-6])

Plugging this into your regex from above, we get this (running in chrome devtools console):

new RegExp(
    "^"
  + "[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}"
  + ":"
  + "([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-6])"
  + ":"
  + "([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-6])"
  + "$"
).test("7e21dc49-8640-4982-b3eb-51608b680e3c:1:65536")

>> true

Full regex:

^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}:([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-6]):([1-9]|[1-8][0-9]|9[0-9]|[1-8][0-9]{2}|9[0-8][0-9]|99[0-9]|[1-8][0-9]{3}|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9]|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-6])$
evnp
  • 191
  • 1
  • 6
  • Thanks for your help but it is terrible – Я TChebur Sep 11 '20 at 16:58
  • 1
    Agreed :) I'll reiterate from above - `I'd recommend validating the numeric values in some other way if possible`. Regex is not a great tool for the job here. – evnp Sep 11 '20 at 17:06
  • Ok, so could you please with regex to get guid and 2 number without range? Is it ok `^[A-Za-z0-9-]{36}:\d+:\d+`? – Я TChebur Sep 11 '20 at 17:09
  • Sure, to match any 1 to 5 digit integer would be `[1-9][0-9]{0,4}`. This will match "99999" so you'll have to validate the values are <= 65536 separately. – evnp Sep 11 '20 at 17:14
  • Full regex: `^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}:[1-9][0-9]{0,4}:[1-9][0-9]{0,4}$` – evnp Sep 11 '20 at 17:15
  • 1
    The reason `\d+` is not ideal is that it will match things you probably don't want, like "00653", "123456789", and "0". It might work for you if you're doing separate validation though. – evnp Sep 11 '20 at 17:18
  • Is it valid to use this shorter `^[A-Za-z0-9-]{36}` to check GUID? – Я TChebur Sep 11 '20 at 21:00
  • 1
    It really depends, that will match non-guid strings like "123e4567e89b12d3a4569AC7CBDCEE52" (as opposed to "123e4567-e89b-12d3-a456-9AC7CBDCEE52" with hyphens) which you might not want to match--for instance, 36 non-hyphen characters is not a valid GUID. If you consider those to both be valid GUIDs then it's fine; if you require hyphens then you'll need your longer original regex. Here's more information about GUIDs: https://stackoverflow.com/questions/417108/why-are-there-dashes-in-a-net-guid – evnp Sep 12 '20 at 00:08
2

There is no language specified, but you might also use a broader match with 2 capturing groups where each of the match for a number starts at 1, and using code you could check if the values from the group are lower or equal than 65536.

^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}:([1-9][0-9]*):([1-9][0-9]*)$

Explanation

  • ^ Start of string
  • [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12} Match the guid format
  • :([1-9][0-9]*) Match : and capture group 1 to match a number starting from 1
  • :([1-9][0-9]*) Match : and capture group 2 to match a number starting from 1
  • $ End of string

For example using C# (It is listed as your top tag)

string pattern = @"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}:([1-9][0-9]*):([1-9][0-9]*)$";
string s = @"123e4567-e89b-12d3-a456-9AC7CBDCEE52:21:4552";
int n1;
int n2;

Match m = Regex.Match(s, pattern);

if (m.Success && Int32.TryParse(m.Groups[1].Value, out n1) && Int32.TryParse(m.Groups[1].Value, out n2)) {
    if (n1 <= 65536 && n2 <= 65536) {
        Console.WriteLine("Match");
    }
}

Output

Match
The fourth bird
  • 154,723
  • 16
  • 55
  • 70