如何测试有效的 UUID/GUID?

Posted

技术标签:

【中文标题】如何测试有效的 UUID/GUID?【英文标题】:How to test valid UUID/GUID? 【发布时间】:2011-12-15 21:30:46 【问题描述】:

如何检查变量是否包含有效的 UUID/GUID 标识符?

我目前只对验证类型 1 和 4 感兴趣,但这不应该限制您的答案。

【问题讨论】:

字符串格式,不是十六进制,不是bin,或者我不知道你要什么 如果您无法排除包含 32 个连续十六进制数字链的变量(不分组),请查看 my answer 可能会有帮助:npmjs.com/package/uuid-validate 【参考方案1】:

版本 1 到 5,省略版本时不使用多版本正则表达式。

const uuid_patterns = 
  1: /^[0-9A-F]8-[0-9A-F]4-1[0-9A-F]3-[0-9A-F]4-[0-9A-F]12$/i,
  2: /^[0-9A-F]8-[0-9A-F]4-2[0-9A-F]3-[0-9A-F]4-[0-9A-F]12$/i,
  3: /^[0-9A-F]8-[0-9A-F]4-3[0-9A-F]3-[0-9A-F]4-[0-9A-F]12$/i,
  4: /^[0-9A-F]8-[0-9A-F]4-4[0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i,
  5: /^[0-9A-F]8-[0-9A-F]4-5[0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i
;

const isUUID = (input, version) =>     
    if(typeof input === "string")
        if(Object.keys(uuid_patterns).includes(typeof version === "string" ? version : String(version)))
            return uuid_patterns[version].test(input);
         else 
            return Object.values(uuid_patterns).some(pattern => pattern.test(input));
        
    
    return false;


// Testing
let valid = [
    'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
    'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
    'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
];

let invalid = [
    '',
    'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3',
    'A987FBC9-4BED-3078-CF07-9141BA07C9F3xxx',
    'A987FBC94BED3078CF079141BA07C9F3',
    '934859',
    '987FBC9-4BED-3078-CF07A-9141BA07C9F3',
    'AAAAAAAA-1111-1111-AAAG-111111111111',
];

valid.forEach(test => console.log("Valid case, result: "+isUUID(test)));
invalid.forEach(test => console.log("Invalid case, result: "+isUUID(test)));

【讨论】:

【参考方案2】:

如果你使用 uuid 包,你可以导入 validate 并将 id 传入其中

const  v4: uuidv4, validate  = require('uuid');

const  id  = request.params;
validate(id) ? true : false;

【讨论】:

【参考方案3】:

如果你使用 uuid 包,这个包会带来一个布尔验证函数,它会告诉你一个 uuid 是否有效。

例子:

import  validate as isValidUUID  from 'uuid';

if (!isValidUUID(tx.originId)) 
  return Promise.reject('Invalid OriginID');

【讨论】:

太棒了!对于我们这些已经在 J​​S 中生成 UUID 的人来说,这比公认的解决方案要好。 是 2012 年的解决方案 效果很好!!!【参考方案4】:

在 Node 中执行此操作的一个好方法是使用 ajv 包 (https://github.com/epoberezkin/ajv)。

const Ajv = require('ajv');
const ajv = new Ajv( allErrors: true, useDefaults: true, verbose: true );
const uuidSchema =  type: 'string', format: 'uuid' ;
ajv.validate(uuidSchema, 'bogus'); // returns false
ajv.validate(uuidSchema, 'd42a8273-a4fe-4eb2-b4ee-c1fc57eb9865'); // returns true with v4 GUID
ajv.validate(uuidSchema, '892717ce-3bd8-11ea-b77f-2e728ce88125'); // returns true with a v1 GUID

【讨论】:

谢谢,你能更新你的答案中的一行吗,const ajv = new Ajv( allErrors: true, useDefaults: true, verbose: true ); useDefaults not useDefault 完成 - 如果需要,您现在可以删除您的评论。【参考方案5】:

以更简洁的方式编写的上述答案的略微修改版本。这将验证任何带有连字符的 GUID(但是很容易修改以使连字符成为可选)。这也将支持无论规范如何都已成为惯例的大写和小写字符:

/^([0-9a-fA-F]8)-(([0-9a-fA-F]4\-)3)([0-9a-fA-F]12)$/i

这里的关键是下面的重复部分

(([0-9a-fA-F]4\-)3)

这只是将 4 个字符模式重复 3 次

【讨论】:

A-f 应该是 A-F 就像这样:/^([0-9a-fA-F]8)-(([0-9a-fA-F]4\-)3)([0-9a-fA-F]12)$/i 如果不区分大小写 (/i),为什么要重复 a-f 然后 A-F?【参考方案6】:

使用.match()方法判断String是否为UUID。

public boolean isUUID(String s)
    return s.match("^[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$");

【讨论】:

Uncaught TypeError: s.matches is not a function 给定的脚本不是 javascript,这是 OP 要求的。 针对上述 cmets 的调整答案。解决方案现在按预期工作。 那还不是js。 @ktilcu 这是在 JS 中 const isUUID = (uuid) => return uuid.match( '^[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$' ); ;【参考方案7】:

我认为Gambol's answer 几乎是完美的,但它有点误解了RFC 4122 § 4.1.1. Variant section。

它涵盖 Variant-1 UUID (10xx = 8..b),但不涵盖 Variant-0 (0xxx = 0..7) 和 Variant-2 (110x = c..d) 变体向后兼容性,因此它们在技术上是有效的 UUID。 Variant-4 (111x = e..f) 确实保留供将来使用,因此它们目前无效。

另外,0 类型是无效的,“数字”只有在它是 NIL UUID 时才允许为 0(如 Evan's answer 中提到的)。

所以我认为符合当前 RFC 4122 规范的最准确的正则表达式是(包括连字符):

/^([0-9a-f]8-[0-9a-f]4-[1-5][0-9a-f]3-[0-9a-d][0-9a-f]3-[0-9a-f]12|00000000-0000-0000-0000-000000000000)$/i
                            ^                ^^^^^^
                    (0 type is not valid)  (only e..f variant digit is invalid currently)

【讨论】:

【参考方案8】:

目前,UUID 是在 RFC4122 中指定的。一个经常被忽视的边缘情况是 NIL UUID,注意到here。以下正则表达式考虑了这一点,并将返回 NIL UUID 的匹配项。有关仅接受非 NIL UUID 的 UUID,请参见下文。这两种解决方案都适用于版本 1 到 5(参见第三块的第一个字符)。

因此要验证 UUID...

/^[0-9a-f]8-[0-9a-f]4-[0-5][0-9a-f]3-[089ab][0-9a-f]3-[0-9a-f]12$/i

...确保您有一个规范格式的 UUID,它是版本 1 到 5,并且是符合 RFC4122 的适当变体。

注意:大括号 不是规范的。它们是某些系统和用法的产物。

很容易修改上面的正则表达式来满足原问题的要求。

提示:正则表达式组/捕获

为了避免匹配 NIL UUID:

/^[0-9a-f]8-[0-9a-f]4-[1-5][0-9a-f]3-[89ab][0-9a-f]3-[0-9a-f]12$/i

【讨论】:

我认为 [1-5][0-9a-f]3 不正确。我有一个有效的 UUID,其中包含“b06a”,这对我来说失败了。 @FelipeBrahm,[1-5] 根据 RFC 是对的,4 位表示版本,只有 5 个版本。 749d0000-0194-1005-2e05-08d61613bf2f 对我来说失败了 出于好奇,(为什么)以下内容也无效:[0-9a-f]8-[0-9a-f]4-[0-9a-f]4-[0-9a-f]4-[0-9a-f]12 @mshaffer 第 21 行,第二个正则表达式定义似乎不正确,第一个没问题 - 验证空正则表达式和抢劫正则表达式,第二个 def 未能做到。【参考方案9】:

我认为更好的方法是使用静态方法 fromString 来避免那些正则表达式。

    id = UUID.randomUUID();
    UUID uuid = UUID.fromString(id.toString());
    Assert.assertEquals(id.toString(), uuid.toString());

另一方面

   UUID uuidFalse = UUID.fromString("x");

抛出 java.lang.IllegalArgumentException:无效的 UUID 字符串:x

【讨论】:

【参考方案10】:

感谢@usertatha 做了一些修改

function isUUID ( uuid ) 
    let s = "" + uuid;

    s = s.match('^[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$');
    if (s === null) 
      return false;
    
    return true;


【讨论】:

你可以使用 .test() 而不是 .match() 并返回它。【参考方案11】:

到目前为止发布的所有类型特定的正则表达式都在“类型 0”Nil UUID 上失败,在 RFC 的 4.1.7 中定义为:

nil UUID 是 UUID 的特殊形式,指定将所有 128 位设置为零:00000000-0000-0000-0000-000000000000

修改 Wolf 的答案:

/^[0-9a-f]8-?[0-9a-f]4-?[0-5][0-9a-f]3-?[089ab][0-9a-f]3-?[0-9a-f]12$/i

或者,要正确排除没有全零的“类型 0”,我们有以下内容(感谢 Luke):

/^(?:[0-9a-f]8-?[0-9a-f]4-?[1-5][0-9a-f]3-?[89ab][0-9a‌​-f]3-?[0-9a-f]12‌​|00000000-0000-0000-‌​0000-000000000000)$/‌​i

【讨论】:

nil UUID 的第一个 UUID 段应该有 8 个零,而不是 7。提供的正则表达式没有用 7 验证它。 你的看起来更好,但允许一些无效的 UUID,例如:abcdef00-0000-0000-0000-000000000000 将匹配你的正则表达式。此正则表达式将匹配有效的 UUID,包括 nil:/^(?:[0-9a-f]8-?[0-9a-f]4-?[1-5][0-9a-f]3-?[89ab][0-9a-f]3-?[0-9a-f]12|00000000-0000-0000-0000-000000000000)$/i【参考方案12】:

如果您想检查或验证特定的 UUID 版本,这里是相应的正则表达式。

请注意,唯一的区别是版本号,在UUID 4122 RFC 的4.1.3. Version 章节中有说明。

版本号是第三组的第一个字符:[VERSION_NUMBER][0-9A-F]3

UUID v1:

/^[0-9A-F]8-[0-9A-F]4-[1][0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i

UUID v2:

/^[0-9A-F]8-[0-9A-F]4-[2][0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i

UUID v3:

/^[0-9A-F]8-[0-9A-F]4-[3][0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i

UUID v4:

/^[0-9A-F]8-[0-9A-F]4-[4][0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i

UUID v5:

/^[0-9A-F]8-[0-9A-F]4-[5][0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i

【讨论】:

有趣的是,我有一个由 C# 创建的 Guid,它与其中任何一个都不匹配,因为它有一个“c”,正则表达式需要 8,9,A 或 B。【参考方案13】:

除了Gambol's answer 几乎在所有情况下都可以完成这项工作,到目前为止给出的所有答案都错过了分组格式 (8-4-4-4-12) 对 @ 不是强制性的987654322@。它的使用非常频繁,但显然 32 位十六进制数字的普通链也是有效的。[1]regexenh

/^[0-9a-f]8-?[0-9a-f]4-?[1-5][0-9a-f]3-?[89ab][0-9a-f]3-?[0-9a-f]12$/i

[1]问题是关于检查变量,所以我们也应该包括对用户不友好的表单。

Why are there dashes in a .NET GUID? - Stack Overflow 加上Accepted answer Test and validate a GUID (guid.us) Guid.ToString Method (String) (MSDN)

【讨论】:

这是我的最爱。更好?[0-9a-f]8-?[0-9a-f]4-?[1-5][0-9a-f]3-?[89ab][0-9a-f]3-?[0-9a-f]12?【参考方案14】:

如果您使用 Node.js 进行开发,建议使用名为 Validator 的包。它包括验证不同版本的 UUID 所需的所有正则表达式,此外您还可以获得各种其他验证函数。

这里是 npm 链接:Validator

var a = 'd3aa88e2-c754-41e0-8ba6-4198a34aa0a2'
v.isUUID(a)
true
v.isUUID('abc')
false
v.isNull(a)
false

【讨论】:

很有趣,但它看起来需要连字符? Here are the four regexes it's currently using -- /^[0-9A-F]8-[0-9A-F]4-3[0-9A-F]3-[0-9A-F]4-[0-9A-F]12$/i 和/或 /^[0-9A-F]8-[0-9A-F]4-4[0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i 和/或 /^[0-9A-F]8-[0-9A-F]4-5[0-9A-F]3-[89AB][0-9A-F]3-[0-9A-F]12$/i 和/或 /^[0-9A-F]8-[0-9A-F]4-[0-9A-F]4-[0-9A-F]4-[0-9A-F]12$/i 验证器只支持 UUID v3-5 不支持 v1【参考方案15】:

正则表达式来救援

/^[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$/.test('01234567-9ABC-DEF0-1234-56789ABCDEF0');

或带括号

/^\?[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\?$/.test('01234567-9ABC-DEF0-1234 -56789ABCDEF0'); 这不太正确。它错过了 [1-5](版本)开始第 3 个块,而 [89AB](变体)开始第 4 个块。 Gambol's answer 做得对。 更简洁的版本(忽略括号):/^[0-9a-f]8-([0-9a-f]4-)3[0-9a-f]12$/i

以上是关于如何测试有效的 UUID/GUID?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Keycloak 获取用户 ID 和用户 UUID/GUID?

聊聊用 UUID/GUID 作为主键那些坑

生成订单号,要求是唯一的,如何实现?

UUID生成随机数工具类

PHP生成 uuid

Golang常用库之UUID