目的
UUIDは様々なシステムで広く使われていますが、URLのパラメータとして渡そうとする時はやはりサイズが長いと思っています。
UUIDのバイナリー本質は16バイトの文字列なので、その素のデータを渡せば、かなり短縮できると考えています。
方法
For JS
UUID <=> Base64
const uuid = require('uuid');
// UUID => Binary Array => Base64 Str(URL-safe)
const binArray = uuid.parse('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b');
// Uint8Array(16) [
// 110, 192, 189, 127, 17,
// 192, 67, 218, 151, 94,
// 42, 138, 217, 235, 174,
// 11
// ]
function base64encode(binaryArray) {
const b64Str = btoa([...binaryArray].map(n => String.fromCharCode(n)).join(""));
return b64Str.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '');
}
console.log(base64encode(binArray));
// 'bsC9fxHAQ9qXXiqK2euuCw'
// Base64 Str(URL-safe) => Binary Array => UUID
function base64decode(base64Str) {
let str = base64Str.replace(/-/g, '+').replace(/_/g, '/');
if (str.length % 4) str += '='.repeat(4 - str.length % 4); // pad with '='
const binArr = atob(str).split('').map(c => c.charCodeAt(0));
return new Uint8Array(binArr);
}
const uuidBin = base64decode('bsC9fxHAQ9qXXiqK2euuCw');
// Uint8Array(16) [
// 110, 192, 189, 127, 17,
// 192, 67, 218, 151, 94,
// 42, 138, 217, 235, 174,
// 11
// ]
console.log(uuid.stringify(uuidBin));
// '6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b'
For Ruby
UUID <=> Base64
# NPM package "uuid" の "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b" を例として
uuid = "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b" # 36文字
require "base64"
## UUID => BinaryStr => Base64 (URL Safe)
### uuidをBinaryStrに変換
bin_str = [uuid.gsub("-", "")].pack("H*")
# => "n\xC0\xBD\x7F\x11\xC0C\xDA\x97^*\x8A\xD9\xEB\xAE\v"
### Base64 (URL Safe) に変換
b64_str = Base64.urlsafe_encode64(bin_str, padding: false)
# => "bsC9fxHAQ9qXXiqK2euuCw" # 22文字、約40%圧縮
## Base64 (URL Safe) => ByteArray => UUID
### Base64 (URL Safe) からバイト列に変換
byte_arr = Base64.urlsafe_decode64("bsC9fxHAQ9qXXiqK2euuCw").unpack("C*")
# => [110, 192, 189, 127, 17, 192, 67, 218, 151, 94, 42, 138, 217, 235, 174, 11]
### バイト列を元にUUID文字列を生成
# positions = [[3, 2, 1, 0], [5, 4], [7, 6], [8, 9], 10..15] # C#のGUIDの仕様
positions = [0..3, 4..5, 6..7, 8..9, 10..15] # NPM package "uuid" の仕様 ("uuid.stringify()" に準拠)
uuid_str = positions.map {| a | a.map {| n | "%02x" % byte_arr[n] }.join }.join("-")
# => "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b"
Base64版UUID(もどき)を直接発行(厳密ではない)
require "securerandom"
require "base64"
# SecureRandom.uuid を使わず、Base64版を直接発行
SecureRandom.urlsafe_base64(16, false)
# => "h8JcfNDRGzoPc3pNiV88Bw"
# Base64版をUUIDに変換
arr = Base64.urlsafe_decode64("h8JcfNDRGzoPc3pNiV88Bw").unpack("C*")
[0..3, 4..5, 6..7, 8..9, 10..15].map {| a | a.map {| n | "%02x" % arr[n] }.join }.join("-")
# => "87c25c7c-d0d1-1b3a-0f73-7a4d895f3c07"
For Python
UUID <=> Base64
import base64
import uuid
uuid_str = "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b"
uuid_bytes = uuid.UUID(uuid_str).bytes
[int(byte) for byte in uuid_bytes]
# [110, 192, 189, 127, 17, 192, 67, 218, 151, 94, 42, 138, 217, 235, 174, 11]
base64_str = base64.urlsafe_b64encode(uuid_bytes).rstrip(b'=').decode('utf-8')
# bsC9fxHAQ9qXXiqK2euuCw
padding = '=' * ((4 - len(base64_str) % 4) % 4)
uuid_bytes = base64.urlsafe_b64decode(base64_str + padding)
uuid.UUID(bytes=uuid_bytes)
# UUID('6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b')
メソッド化
下記コードはGitHub Copilotより生成
import base64
import uuid
# UUID => Binary Array => Base64 Str (URL-safe)
def uuid_to_base64(uuid_str):
# Convert UUID string to bytes
uuid_bytes = uuid.UUID(uuid_str).bytes
# Encode bytes to Base64 (URL-safe)
base64_str = base64.urlsafe_b64encode(uuid_bytes).rstrip(b'=').decode('utf-8')
return base64_str
# Base64 Str (URL-safe) => Binary Array => UUID
def base64_to_uuid(base64_str):
# Decode Base64 (URL-safe) to bytes
padding = '=' * ((4 - len(base64_str) % 4) % 4) # Add padding if necessary
uuid_bytes = base64.urlsafe_b64decode(base64_str + padding)
# Convert bytes to UUID string
return str(uuid.UUID(bytes=uuid_bytes))
# Example usage
original_uuid = "6ec0bd7f-11c0-43da-975e-2a8ad9ebae0b"
print("Original UUID:", original_uuid)
# Convert UUID to Base64
base64_str = uuid_to_base64(original_uuid)
print("Base64 (URL-safe):", base64_str)
# Convert Base64 back to UUID
converted_uuid = base64_to_uuid(base64_str)
print("Converted UUID:", converted_uuid)
あわせ読み
参考
JS
- JS/TSでバイナリ⇔BASE64はライブラリを使わなくても簡単に出来る
- Convert UUID to/from binary in Node
- Remove trailing "=" when base64 encoding
Ruby
- Base64.#urlsafe_encode64
- MDN Web Docs 用語集 > Base64
- module SecureRandom
- singleton method SecureRandom.uuid
- How to create ruby uuid from bytes?
- Convert a string of 0-F into a byte array in Ruby
- instance method String#unpack