ThirtyTo

ThirtyTo

用于数据和标识符的 Base32Crockford 编码的 Swift 包。

SwiftPM Twitter GitHub GitHub issues GitHub Workflow Status

Codecov CodeFactor Grade codebeat badge Code Climate maintainability Code Climate technical debt Code Climate issues Reviewed by Hound

目录

简介

ThirtyTo 提供了一种编码数据和创建标识符的方法,既高效又具有可读性。虽然 Base64 更高效,但由于同时包含大小写字母和标点符号,因此可读性不强。

要求

Apple 平台

Linux

安装

使用 Swift Package Manager 通过存储库 URL 安装此库

https://github.com/brightdigit/ThirtyTo.git

使用最高到 1.0 的版本。

为什么使用 Base32Crockford

在编码数据方面,Base32Crockford 提供了最合理的折衷方案。 作为 Base16 的超集,它使用所有十个数字和 26 个拉丁字母大写字符中的 22 个。

符号值 解码符号 编码符号
0 0 O o 0
1 1 I i L l 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 9 9
10 A a A
11 B b B
12 C c C
13 D d D
14 E e E
15 F f F
16 G g G
17 H h H
18 J j J
19 K k K
20 M m M
21 N n N
22 P p P
23 Q q Q
24 R r R
25 S s S
26 T t T
27 V v V
28 W w W
29 X x X
30 Y y Y
31 Z z Z

用法

ThirtyTo 能够以 Base32Crockford 编码和解码数据,以及创建唯一标识符。 有多种编码和解码选项可用。

编码和解码数据

所有编码和解码都通过 Base32CrockfordEncoding.encoding 对象完成。 这提供了编码和解码数据以及标准化的接口。

要编码任何数据,请调用

public func encode(
    data: Data,
    options: Base32CrockfordEncodingOptions = .none
  ) -> String

因此,要编码 Data 对象,只需通过以下方式调用

let data : Data // 0x00b003786a8d4aa28411f4e268c43629 
let base32String = Base32CrockfordEncoding.encoding.encode(data: data)
print(base32String) // P01QGTMD9AH884FMW9MC8DH9

如果要解码字符串,可以调用 Base32CrockfordEncoding.decode

let data = try Base32CrockfordEncoding.encoding.decode(
    base32Encoded: "P01QGTMD9AH884FMW9MC8DH9"
) // 0x00b003786a8d4aa28411f4e268c43629

Base32CrockfordEncoding.encode 对象提供了指定格式选项和校验和的功能。

校验和工作原理

您可以选择在末尾提供校验和字符,以便尽早且经济地检测传输和输入错误。

根据规范

校验符号编码模 37 的数字,37 是大于 32 的最小素数。我们引入了 5 个额外的符号,这些符号仅用于编码或解码校验符号。

额外的 5 个符号是

符号值 解码符号 编码符号
32 * *
33 ~ ~
34 $ $
35 = =
36 U u U

如果要包含校验和,请为 Base32CrockfordEncodingOptions 对象上的 withChecksum 属性传递 true

let data : Data // 0xb63d798c4329401684d1d41d3becc95c
let base32String = Base32CrockfordEncoding.encoding.encode(
    data: data,
    options: .init(withChecksum: true)
)
print(base32String) // 5P7NWRRGS980B89MEM3MXYSJAW5

解码带有校验和的字符串时,必须为 Base32CrockfordDecodingOptions 上的 withChecksum 属性指定 true

let data = try Base32CrockfordEncoding.encoding.decode(
    base32Encoded: "5P7NWRRGS980B89MEM3MXYSJAW5"a,
    options: .init(withChecksum: true)
) // 0xb63d798c4329401684d1d41d3becc95c

除了添加校验和之外,Base32CrockfordEncodingOptions 还提供了添加分组分隔符的功能。

使用分组分隔符

根据 Base32Crockford 规范

连字符 (-) 可以插入到符号字符串中。 这可以将字符串划分为可管理的部分,通过帮助防止混淆来提高可读性。 解码期间将忽略连字符。

要将连字符插入到编码字符串中,请将 GroupingOptions 对象提供给 Base32CrockfordEncodingOptions

let data : Data // 00c9c37484b85a42e8b3e7fbf806f2661b
let base32StringGroupedBy3 = Base32CrockfordEncoding.encoding.encode(
    data: data,
    options: .init(groupingBy: .init(maxLength: 3))
)
let base32StringGroupedBy9 = Base32CrockfordEncoding.encoding.encode(
    data: data,
    options: .init(groupingBy: .init(maxLength: 9))
)
print(base32StringGroupedBy3) // 69R-DT8-9E2-T8B-MB7-SZV-Z03-F4S-GV2
print(base32StringGroupedBy9) // 69RDT89E2-T8BMB7SZV-Z03F4SGV2

解码时,将忽略连字符

let dataNoHyphens = try Base32CrockfordEncoding.encoding.decode(
    base32Encoded: "69RDT89E2T8BMB7SZVZ03F4SGV2"
) // 00c9c37484b85a42e8b3e7fbf806f2661b

let dataGroupedBy3 = try Base32CrockfordEncoding.encoding.decode(
    base32Encoded: "69R-DT8-9E2-T8B-MB7-SZV-Z03-F4S-GV2"
) // 00c9c37484b85a42e8b3e7fbf806f2661b

let dataGroupedBy9 = try Base32CrockfordEncoding.encoding.decode(
    base32Encoded: "69RDT89E2-T8BMB7SZV-Z03F4SGV2"
) // 00c9c37484b85a42e8b3e7fbf806f2661b

assert(dataNoHyphens == dataGroupedBy3) // true
assert(dataNoHyphens == dataGroupedBy9) // true
assert(dataGroupedBy3 == dataGroupedBy9) // true

创建标识符

ThirtyTo 提供了在通用工厂中创建不同类型标识符的功能。 虽然开发人员可以使用 UUID,但此库提供了一个接口来创建其他两种类型。 为此,您可以调用 IdentifierFactory/createIdentifier(with:)Identifier/factory 上创建提供的三种类型中的任何一种

每种类型都有相应的 ComposableIdentifier/Specifications

这是一个 UDID 的示例

// create an identifier for 1 million unique IDs that is a factor of 5.
let specs = AnyIdentifierSpecifications(
  size: .minimumCount(1_000_000, factorOf: 5)
)
let identifier: UDID = Identifier.factory.createIdentifier(with: specs)

什么是 ULID?

ULID 的目的是解决 UUID 的几个问题,同时保持兼容性

最重要的是,它使用 Base32Crockford 以获得更好的效率和可读性。

要创建 ULID,您可以使用 IdentifierFactory.createIdentifier(with:)Identifier.factory

let ulid : ULID = Identifier.factory.createIdentifier(with: .parts(nil, .random(nil)))

或构造函数

let ulid = ULID(specifications: .parts(nil, .random(nil)))

在大多数情况下,默认的 ULID.Specifications.default 规范就足够了。 这遵循规范规范,该规范使用前 6 个字节作为时间戳,最后 10 个字节是随机的。 否则,您可以使用 ULID.Specifications.data(_:) 指定所有 16 个字节,或者指定用于时间戳的 Date 和用于数据的 ULID.randomPartRandomDataGenerator

参考

许可证

此代码在 MIT 许可下分发。 有关更多信息,请参见 LICENSE 文件。