38

I have the following piece of code:

func GetUUIDValidator(text string) bool { r, _ := regexp.Compile("/[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}/") return r.Match([]byte(text)) } 

But when I pass fbd3036f-0f1c-4e98-b71c-d4cd61213f90 as a value, I got false, while indeed it is an UUID v4.

What am I doing wrong?

1
  • 3
    BTW, there is regex.MustCompile for usage like the one in your code. Also, Go style regexes don't use // delimiters. Read the documentation to understand how Go regex work. Commented Jul 31, 2014 at 7:16

5 Answers 5

112

Regex is expensive. The following approach is ~18x times faster than the regex version.

Use something like https://godoc.org/github.com/google/uuid#Validate instead.

import "github.com/google/uuid" if err := uuid.Validate("uuid..."); err == nil { // valid UUID } 

[Jan 2025] Updated to use Validate instead of Parse, which was added in v1.5.0.

Sign up to request clarification or add additional context in comments.

3 Comments

Good but also introduce a dependency to another library.
Any examples on why RegExp would be expensive? You do know that in Go RegExps are constant in time depending on the input, right?
I believe Go's implementation is linear O(n) not constant O(1). Since UUIDs are fixed size, I don't think it matters too much anyway. I ran a quick benchmark, it's 628 ns/op for the regexp version and 34.8 ns/op for the "uuid.Parse" approach. gist.github.com/mattes/69a4ab7027b9e8ee952b5843e7ca6955
49

Try with...

func IsValidUUID(uuid string) bool { r := regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-4[a-fA-F0-9]{3}-[8|9|aA|bB][a-fA-F0-9]{3}-[a-fA-F0-9]{12}$") return r.MatchString(uuid) } 

Live example: https://play.golang.org/p/a4Z-Jn4EvG

Note: as others have said, validating UUIDs with regular expressions can be slow. Consider other options too if you need better performance.

9 Comments

You're checking [1-5] in the third section, which allows this to match for non uuid 4 strings. The title of this question asks for uuid v4. Change [1-5] to 4 and it works as requested.
Thanks @Marc. Just updated it, plus updated the 4th section too.
Unfortunately this regex is incorrect in that it matches a larger set of strings than valid UUID. for example if the starting chunk is larger than 8 characters it will still match. you will want regexp.MustCompile("^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[8|9|a|b][a-f0-9]{3}-[a-f0-9]{12}$")
@ForeverStudent you're right! I'm updating the answer. Thank you for your contribution.
One more thing: sometimes you use [a-f] and sometimes [aAbB], thereby allowing uppercase letters only in a few places.
|
9

You can utilize satori/go.uuid package to accomplish this:

import "github.com/satori/go.uuid" func IsValidUUID(u string) bool { _, err := uuid.FromString(u) return err == nil } 

This package is widely used for UUID operations: https://github.com/satori/go.uuid

1 Comment

I updated gist.github.com/mattes/69a4ab7027b9e8ee952b5843e7ca6955 to benchmark satori/go.uuid vs google/uuid. Google's UUID check is 3.3x faster than this one.
5

In case you would be validating it as attribute of a struct, there is an awesome golang library straight from the Go called validator https://godoc.org/gopkg.in/go-playground/validator.v9 which you can use to validate all kinds of fields nested structures by provided built-in validators as well as complete custom validation methods. All you need to do is just add proper tags to the fields

import "gopkg.in/go-playground/validator.v9" type myObject struct { UID string `validate:"required,uuid4"` } func validate(obj *myObject) { validate := validator.New() err := validate.Struct(obj) } 

It provides structured field errors and other relevant data from it.

1 Comment

validator.v10 is out (v9 is on maintenance only since 2019, meaning it won't receive any further features, just bug & security fixes), although the docs still refer to v9!
0

Since Dec 12, 2023 there is a new feature to validate directly by string: https://github.com/google/uuid/commit/9ee7366e66c9ad96bab89139418a713dc584ae29

var string anyUUID = "elmo" err := uuid.Validate(anyUUID) // will result in an error 

Live example: https://go.dev/play/p/QIzW63S0Oda

This is very useful when it comes to testing:

assert.NoError(t, uuid.Validate(anyUUID)) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.