如何将 UUID 类型转换为 ULID 类型?

问题描述 投票:0回答:4

有一些文档介绍如何将 ULID 转换为 UUID,但当您需要将 UUID 转换为 ULID 时却没有那么多文档。

我正在查看这个 UUID / ULID 生成器/转换器 https://www.ulidtools.com/

但我不太确定如何将 UUID 复制到 ULID 转换,源代码太模糊了,我无法理解。

我不知道从哪里开始,这种转换安全吗?它能保证唯一的转换吗?

javascript uuid ulid
4个回答
2
投票

我也遇到了同样的问题,我查看了 ulidtools.com,然后在深入研究其源代码一段时间后,我发现它在所见的后面使用了 this package

import pkg from "id128";
const { Ulid, Uuid4 } = pkg;

const ulid = Ulid.generate();
const ulidToUuid = Uuid4.fromRaw(ulid.toRaw());
const uuidToUlid = Ulid.fromRaw(ulidToUuid.toRaw());

console.table([
  {
    generated_ulid: ulid.toCanonical(),
    converted_to_uuid: ulidToUuid.toCanonical(),
    converted_back_to_ulid: uuidToUlid.toCanonical(),
  },
]);


1
投票

根据@ImanHosseiniPour 的回答,我得出以下结论:

时间戳 + UUID = ULID

import { Ulid, Uuid4 } from "id128";
import { factory, decodeTime } from 'ulid'

const genUlid = factory();

function convertUuidToUlid(
  timestamp: Date, 
  canonicalUuid: string,
): Ulid {
  const uuid = Uuid4.fromCanonical(canonicalUuid);
  const convertedUlid = Ulid.fromRaw(uuid.toRaw())
  const ulidTimestamp = genUlid(timestamp.valueOf()).slice(0, 10)
  const ulidRandom = convertedUlid.toCanonical().slice(10);
  
  return Ulid.fromCanonical(ulidTimestamp + ulidRandom)
}

const timestamp = new Date()
const uuid = 'f0df59ea-bfe2-43a8-98d4-8213348daeb6'
const ulid = convertUuidToUlid(timestamp, uuid)
const originalUuid = Uuid4.fromRaw(ulid.toRaw());

console.table({
  timestamp: timestamp.valueOf(),
  uuid,
  ulid: ulid.toCanonical(),
  decodedTime: decodeTime(ulid.toCanonical()),
  originalUuid: originalUuid.toCanonical(),
});

请记住,由于我们合并了时间戳,将 ULID 逆向工程为 UUID 将使前两个块与原始块不同


0
投票

纯Javascript转换方法:

将 UUID 转换为 ULID 可保证代码的唯一性。 ULID 是基于当前时间戳的组合生成的唯一 128 位标识符。

function convertUUIDtoULID(uuid) {
  const uuidBinary = uuid.split("-").map((hex) => parseInt(hex, 16));
  return uuidBinary
    .slice(0, 8)
    .map((byte) => byte.toString(32))
    .concat(uuidBinary.slice(8).map((byte) => byte.toString(32)))
    .join("");
}

const uuid = "454391df-b950-42ea-a2c0-92d62c215d67";
const ulid = convertUUIDtoULID(uuid);
console.log(ulid);
  • 该函数接受 UUID 格式的字符串作为输入
  • 它在每个“-”字符处分割 UUID 字符串并转换每个 使用以下命令将结果十六进制字符串转换为十进制数 以 16 为基数的 parseInt() 函数。
  • 它根据 UUID 创建一个包含前 8 个十进制数的新数组 并使用 toString() 将每个数字转换为以 32 为基数的字符串 以 32 为底的函数。
  • 它将这个数组与剩余小数的新数组连接起来 UUID 中的数字,也转换为 base-32 字符串。
  • 生成的 32 进制字符串数组连接在一起形成一个 单个字符串,作为 ULID 返回。
  • 示例 UUID 字符串被传递到函数中,结果是 ULID 字符串记录到控制台。

您还可以使用[https://www.npmjs.com/package/ulid]将UUID转换为ULID


0
投票

这个问题的其他答案没有满足我的需求(没有外部依赖)。这是一个适用于 vanilla ECMAScript2018 JS 的版本:

/**
 * Decodes a hexadecimal string (case-insensitive) into an equivalent Uint8Array.
 * 
 * @param {string} hexString The string to decode
 * @returns {Uint8Array} The string decoded into binary
 */
function decodeHex(hexString) {
    if (typeof hexString !== 'string' || hexString.length % 2 !== 0) {
        throw new Error('Invalid hex string');
    }

    const decoded = new Uint8Array(hexString.length / 2);

    for (let i = 0; i < hexString.length; i += 2) {
        const byte = parseInt(hexString.substring(i, i + 2), 16);
        decoded[i / 2] = byte;
    }

    return decoded;
}


/**
 * The ULID encoding lookup. Notably excludes I, L, U, and O.
 */
const ULID_ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';

/**
 * Converts a UUID to an equivalent ULID.
 * 
 * @param {string} uuid The UUID, encoded as a 36-character hex-with-dashes string.
 * @returns {string} The equivalent ULID, encoded as a 26-character base32 string.
 */
function uuidToUlid(uuid) {
    if (!/^[0-9A-Fa-f]{8}(-[0-9A-Fa-f]{4}){3}-[0-9A-Fa-f]{12}$/i.test(uuid)) {
        throw new Error('Invalid UUID.');
    }

    // Break into sections, excluding dashes.
    // Using 0179e73f-ff38-a5e0-e633-48fae1c0bd35 as example...

    const section1 = uuid.substring(0, 8);      // is 0179e73f
    const section2 = uuid.substring(9, 13);     // is ff38
    const section3 = uuid.substring(14, 18);    // is a5e0
    const section4 = uuid.substring(19, 23);    // is e633
    const section5 = uuid.substring(24);        // is 48fae1c0bd35

    // concatenate the parts, decoded into Uint8Array types. This will have length 16.
    const decodedArray = [
        ...decodeHex(section1),
        ...decodeHex(section2),
        ...decodeHex(section3),
        ...decodeHex(section4),
        ...decodeHex(section5),
    ];

    // optimized unrolled loop for converting 16 bytes into 26 characters, using 
    // the ULID lookup to translate from integers [0-25] to valid ULID characters.
    // ref. https://github.com/RobThree/NUlid
    const ulid = [
        ULID_ENCODING[(decodedArray[0] & 224) >> 5],
        ULID_ENCODING[decodedArray[0] & 31],
        ULID_ENCODING[(decodedArray[1] & 248) >> 3],
        ULID_ENCODING[((decodedArray[1] & 7) << 2) | ((decodedArray[2] & 192) >> 6)],
        ULID_ENCODING[(decodedArray[2] & 62) >> 1],
        ULID_ENCODING[((decodedArray[2] & 1) << 4) | ((decodedArray[3] & 240) >> 4)],
        ULID_ENCODING[((decodedArray[3] & 15) << 1) | ((decodedArray[4] & 128) >> 7)],
        ULID_ENCODING[(decodedArray[4] & 124) >> 2],
        ULID_ENCODING[((decodedArray[4] & 3) << 3) | ((decodedArray[5] & 224) >> 5)],
        ULID_ENCODING[decodedArray[5] & 31],
        ULID_ENCODING[(decodedArray[6] & 248) >> 3],
        ULID_ENCODING[((decodedArray[6] & 7) << 2) | ((decodedArray[7] & 192) >> 6)],
        ULID_ENCODING[(decodedArray[7] & 62) >> 1],
        ULID_ENCODING[((decodedArray[7] & 1) << 4) | ((decodedArray[8] & 240) >> 4)],
        ULID_ENCODING[((decodedArray[8] & 15) << 1) | ((decodedArray[9] & 128) >> 7)],
        ULID_ENCODING[(decodedArray[9] & 124) >> 2],
        ULID_ENCODING[((decodedArray[9] & 3) << 3) | ((decodedArray[10] & 224) >> 5)],
        ULID_ENCODING[decodedArray[10] & 31],
        ULID_ENCODING[(decodedArray[11] & 248) >> 3],
        ULID_ENCODING[((decodedArray[11] & 7) << 2) | ((decodedArray[12] & 192) >> 6)],
        ULID_ENCODING[(decodedArray[12] & 62) >> 1],
        ULID_ENCODING[((decodedArray[12] & 1) << 4) | ((decodedArray[13] & 240) >> 4)],
        ULID_ENCODING[((decodedArray[13] & 15) << 1) | ((decodedArray[14] & 128) >> 7)],
        ULID_ENCODING[(decodedArray[14] & 124) >> 2],
        ULID_ENCODING[((decodedArray[14] & 3) << 3) | ((decodedArray[15] & 224) >> 5)],
        ULID_ENCODING[decodedArray[15] & 31]
    ].join('');

    return ulid;
}

const uuid = '0179e73f-ff38-a5e0-e633-48fae1c0bd35';
const ulid = uuidToUlid(uuid);
console.log(ulid); // 01F7KKZZSRMQGECCT8ZBGW1F9N

如果您想验证功能,这里有一个 JSFiddle

© www.soinside.com 2019 - 2024. All rights reserved.