我一直在阅读 http://www.ietf.org/rfc/rfc4122.txt 的 UUID RFC并尝试使用 python uuid 模块。为了便于解释,这里是从规范中提取的 UUID 图。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_low |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time_mid | time_hi_and_version |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|clk_seq_hi_res | clk_seq_low | node (0-1) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| node (2-5) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
根据我对规范的阅读,最小的 1 类 UUID 应该将 time_low、time_mid、clk_seq_hi_res、clk_seq_low 和节点设置为全 0,而 time_hi_and_version 应该将第 15 位设置为 1。最大的 1 类 UUID应该将 time_low、time_mid、clk_seq_hi_res、clk_seq_low 和节点设置为全 1,将 time_hi_and_version 设置为全 1,除了位 12、13 和 14。
但是,尝试在 python 中生成这些失败:
>>> u = uuid.UUID("{00000000-0000-0000-0001-00000000}")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/2.7.4/Frameworks/Python.framework/Versions/2.7/lib/python2.7/uuid.py", line 134, in __init__
raise ValueError('badly formed hexadecimal UUID string')
ValueError: badly formed hexadecimal UUID string
>>> u = uuid.UUID("{ffffffff-ffff-ffff-fff1-ffffffff}")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/python/2.7.4/Frameworks/Python.framework/Versions/2.7/lib/python2.7/uuid.py", line 134, in __init__
raise ValueError('badly formed hexadecimal UUID string')
ValueError: badly formed hexadecimal UUID string
我假设我没有正确阅读规范,但我不知所措。
请您参考如下方法:
问题不在于你的特定值(value)观,而是你没有足够的值(value)观。
您只提供了 14 个字节的数据而不是 16 个,这就是它所提示的。
UUID 根本不检查类型 1 UUID 的要求。如果是这样,它将无法用于具有不同要求的其他 UUID 类型。
试试这个:
In [58]: uuid.UUID("{00000000-0000-0000-0000-000000000000}")
Out[58]: UUID('00000000-0000-0000-0000-000000000000')
In [59]: uuid.UUID('{FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF}')
Out[59]: UUID('ffffffff-ffff-ffff-ffff-ffffffffffff')
与此同时,您显然也混淆了版本和变体,并使字节序倒置。因此,让我们从头开始。
according to my reading of the spec, the smallest type-1 UUID… should have time_low, time_mid, clk_seq_hi_res, clk_seq_low, and node set to all 0s
clk_seq_hi_res是clock_sequence_hi_and_reserved的缩写,在4.1.2节中定义为“与变体复用的时钟序列的高场”。变体在4.1.1中定义,你想要“本文档中指定的变体”,将最高两个位分别设置为1和0。因此,该字段不能全为0,也不能全为1。由于这是最高有效位,而不是最低位,这意味着八位字节 8 的高半字节必须是 (8, 9, a, b) 之一,并不是说低半字节必须是 (1, 5, 9, d) 之一。
, and time_hi_and_version should have bit 15 set to 1.
不是,版本号在4.1.3中描述为时间戳的高4位,版本1定义为0-0-0-1。因此,第 15 位应设置为 0,第 14 位和第 13 位也应设置为 0,第 12 位应设置为 1。这意味着八位位组 6 的整个高位半字节必须为 1,而不是八位位组 7 的低位半字节。
所以:
00000000-0000-1000-8000-000000000000
ffffffff-ffff-1fff-bfff-ffffffffffff
请注意,这些时间戳所代表的日期有点傻。前者是 1582 年 10 月 15 日午夜,后者是 53 世纪。*因此,任何验证版本 1 UUID 的库都可能拒绝它们。
此外,全 0 的节点是全 0 的全局单播 MAC 地址,我不确定这是有效的 IEEE-802 地址。全 1 的节点很好,因为如果您设置多播位,则明确允许您使用随机数。
* 作为各种 BBC documentaries和 associated textbooks解释一下,到 49 世纪,人类将进行时间旅行,这将迫使我们改变我们所有的时间戳技术。
