Saturday, December 29, 2007

C#: Check if a string is a valid GUID

***NOTE*** After a lot of constructive criticism from my fellow blog-posters (and I really do appreciate it all), I am questioning my own post about its effectiveness over something simple like this (which was not unknown though). Please read all the comments for your education if you care to:

public bool CheckGuid(string guidString)
{
try
{
Guid g = new Guid(guidString);
return true;
}
catch
{
return false;
}
}

Here is my original posting:

public bool CheckGuid(string guidString)
{
bool response = false;
try
{
System.Text.RegularExpressions.Regex isGuid =
new System.Text.RegularExpressions.Regex(@"^(\{){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}$",
System.Text.RegularExpressions.RegexOptions.Compiled);
response = isGuid.IsMatch(guidString);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

return response;
}

17 comments:

  1. Your approach seems a little inefficient, maybe something like this might be a bit better?

    public static bool IsValidGuid(string value)
    {
    if (value == null)
    throw new ArgumentNullException("value", "Invalid null value supplied");

    return Regex.IsMatch(value, @"^(\{){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}$", RegexOptions.CultureInvariant);
    }

    ReplyDelete
  2. Thank you. You spared me a big headache...

    ReplyDelete
  3. public bool StringIsGuid(string sString) {
    bool bResult = true;
    try {
    new Guid(sString);
    } catch {
    bResult = false;
    }
    }

    ReplyDelete
  4. Uh, return bResult of course

    ReplyDelete
  5. Dwain,
    Yes, your code will work perfectly. However as you know throwing exception is not always the best and most efficient thing to do. If you do a load test calling this function few thousand times where you would actually check for something that is not a GUID, you would understand what I mean. Hope this helps.

    ReplyDelete
  6. behold.....

    private Boolean IsGuid(String value)
    {
    if(value == null)
    {
    return false;
    }
    return Regex.IsMatch(textBox1.Text.ToString(),@"^?[\da-f]{8}-([\da-f]{4}-){3}[\da-f]{12}?$", RegexOptions.IgnoreCase);

    }

    That should do the trick.

    ReplyDelete
  7. oops, shoulda been...

    private Boolean IsGuid(String value)
    {
    if(value == null)
    {
    return false;
    }
    return Regex.IsMatch(value,@"^?[\da-f]{8}-([\da-f]{4}-){3}[\da-f]{12}?$", RegexOptions.IgnoreCase);

    }

    ReplyDelete
  8. Thanks for all the creative ideas, everyone.

    ReplyDelete
  9. Sadly, the regex allows unmatched curly braces and so this method cannot be used as a reliable means to validate GUIDs.

    You can pass in a string like:

    {1102F615-9508-41EF-9699-B517C09D5FEE

    and the method will return true.

    ReplyDelete
  10. Neil,

    If you'll notice the method signature takes in a string. The purpose being to verify a Guid before passing the String into a Guid object. Also assuming that the data came from serialized data that originated from a Guid object, and was passed in via a Guid.ToString() which returns the value formatted without braces.

    ReplyDelete
  11. Further to my comment, you could change the regex to enforce the use of curly braces. Or change it not to have curly braces at all. You could pass in an extra parameter to the method to to switch between "must have both braces" or "must not have any braces".

    ReplyDelete
  12. Hi Samuel,
    Didn't see your comment before posting my update. My original comment was that, as it stood, you could not rely on that method alone to ensure valid GUIDs. If it passed validation, you would still have needed to do a secondary test. The edit as per my second comment should do the trick.
    Best wishes,
    Neil

    ReplyDelete
  13. Feel free to post the edit...

    ReplyDelete
  14. This pattern enforces braces:

    @"^\{[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}\}$";

    You can probably do something with backreferences to check match "with both braces" and "with no braces".

    ReplyDelete
  15. This pattern will validate any formats that the .NET Guid constructor (new Guid(String)) accepts:

    \A[0-9a-fA-F]{32}|[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-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-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[xX][0-9a-fA-F]{1,8} *, *0[xX][0-9a-fA-F]{1,4} *, *0[xX][0-9a-fA-F]{1,4} *, *\{ *0[xX][0-9a-fA-F]{1,2} *, *0[xX][0-9a-fA-F]{1,2} *, *0[xX][0-9a-fA-F]{1,2} *, *0[xX][0-9a-fA-F]{1,2} *, *0[xX][0-9a-fA-F]{1,2} *, *0[xX][0-9a-fA-F]{1,2} *, *0[xX][0-9a-fA-F]{1,2} *, *0[xX][0-9a-fA-F]{1,2} *\} *\}\z

    The documentation on the Guid Contstructor (String):
    "Parameters
    g
    Type: System.String

    A String that contains a GUID in one of the following formats ('d' represents a hexadecimal digit whose case is ignored):

    32 contiguous digits:

    dddddddddddddddddddddddddddddddd

    -or-

    Groups of 8, 4, 4, 4, and 12 digits with hyphens between the groups. The entire GUID can optionally be enclosed in matching braces or parentheses:

    dddddddd-dddd-dddd-dddd-dddddddddddd

    -or-

    {dddddddd-dddd-dddd-dddd-dddddddddddd}

    -or-

    (dddddddd-dddd-dddd-dddd-dddddddddddd)

    -or-

    Groups of 8, 4, and 4 digits, and a subset of eight groups of 2 digits, with each group prefixed by "0x" or "0X", and separated by commas. The entire GUID, as well as the subset, is enclosed in matching braces:

    {0xdddddddd, 0xdddd, 0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}}

    All braces, commas, and "0x" prefixes are required. All embedded spaces are ignored. All leading zeroes in a group are ignored."

    The question is; Does it perform any better than just doing the following?:
    try {
    Guid g = new Guid(s);
    return true;
    }
    catch {
    return false;
    }

    ReplyDelete
  16. I really appreciate all of you who criticized my post, and more importantly showed your constructive work. I did run some tests with valid as well as invalid GUIDs, and as we kind of expected, the try-catch around new Guid(s) works fastest, especially when the Regex was getting longer and longer to accept all kind of variations.

    So I think we can conclude that if you are OK throwing a first chance exception and handling it within your code, it may not hurt to do so as that way we need not worry about each and every formats.

    However if you do not wish to throw a known exception then you can stick to the format(s) posted.

    ReplyDelete
  17. I do not like using exceptions to do checks and use the following code to do the check:

    Guid g;
    return Guid.TryParse(guidString, out g);

    ReplyDelete

Please use your common sense before making a comment, and I truly appreciate your constructive criticisms.