如何测试有效的 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');
【讨论】:
太棒了!对于我们这些已经在 JS 中生成 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?的主要内容,如果未能解决你的问题,请参考以下文章