SwiftRadix
一个轻量级的库,可以用于使用简单、干净的函数式语法将整数转换为基数字符串(二进制、十六进制、八进制或任何进制)。
摘要
常见用法
统一库,包含多种构造函数,每个函数都提供了库的所有功能。
选项 1:函数 | 选项 2:分类方法 | 返回 |
---|---|---|
Radix(T, base:) |
.radix(base:) |
Radix<T>(base: n) 其中 n 是 2...36 |
Binary(T) |
.binary |
Radix<T>(base: 2) |
Octal(T) |
.octal |
Radix<T>(base: 8) |
Hex(T) |
.hex |
Radix<T>(base: 16) |
为了简化此文档,下文大多数示例将使用 Hex()
/ .hex
。
// convert to or from hex strings
255.hex.stringValue // "FF"
255.hex.stringValue(prefix: true) // "0xFF"
"FF".hex?.value // Optional(255)
"0xFF".hex?.value // Optional(255)
"ZZ".hex?.value // nil (not valid hex string, so init fails)
// work with arrays of any integer type, or hex strings and convert between them
[0, 255, 0, 255].hex.stringValue // "00 FF 00 FF"
[0, 255, 0, 255].hex.stringValues // ["00", "FF", "00", "FF"]
[0, 255, 0, 255].hex.stringValue(prefixes: true) // "0x00 0xFF 0x00 0xFF"
[0, 255, 0, 255].hex.stringValues(prefixes: true) // ["0x00", "0xFF", "0x00", "0xFF"]
[0, 255, 0, 255].hex.stringValueArrayLiteral // "[0x0, 0xFF, 0x0, 0xFF]"
[0, 255, 0, 255].hex.stringValueArrayLiteral(padTo: 2) // "[0x00, 0xFF, 0x00, 0xFF]"
[0, 65535, 4000].hex.stringValue // "0 FFFF FA0"
[0, 65535, 4000].hex.stringValue(padTo: 2) // "00 FFFF FA0"
[0, 65535, 4000].hex.stringValue(padToEvery: 2) // "00 FFFF 0FA0"
[0, 65535, 4000].hex.stringValue(padToEvery: 4) // "0000 FFFF 0FA0"
["00", "FF", "ZZ"].hex.values // [Optional(0), Optional(255), nil]
// test for equatability or perform math operations with great flexibility,
// without needing to extract the .value first, casting or converting
UInt8(123).hex == Int16(123) // true
"FF".hex == 255 // true
123.hex + 10.binary - 10 // 123
安装
Swift 包管理器 (SPM)
-
使用 Swift Package Manager 将 SwiftRadix 添加为依赖项。
-
在一个应用程序项目或框架中,在 Xcode
- 选择菜单:文件 → Swift 包 → 添加依赖项...
- 输入此 URL:
https://github.com/orchetect/SwiftRadix
-
在 Swift 包中,将其添加到 Package.swift 依赖项中
.package(url: "https://github.com/orchetect/SwiftRadix", from: "1.1.0")
-
CocoaPods
pod 'SwiftRadix'
文档
前提
在核心中,一个名为 Radix
的新泛型类型封装了任何 BinaryInteger
值以及与之关联的基数(基数)。
Radix<T: BinaryInteger>
// constructors
Radix(0xFF, base: 16) // Radix<Int>(255)?
Radix(UInt8(0xFF), base: 16) // Radix<UInt8>(255)?
Radix<UInt8>(0xFF, base: 16) // Radix<UInt8>(255)?
Radix(0b1111, base: 2) // Radix<Int>(15)?
// category method to construct
0xFF.radix(base: 16) // Radix<Int>(255)?
0xFF.radix(base: 16, as: UInt8.self) // Radix<UInt8>(255)?
然而,对于常见的基数(二进制基数-2、八进制基数-8、十六进制基数-16),你可能永远不需要直接构造 Radix
。相反,常见类型和集合上提供了方便的功能类别方法来简化解构过程。
255.binary // == Radix<Int>(0b11111111, base: 2)
"0b11111111".binary // == Radix<Int>(255, base: 2)?
255.octal // == Radix<Int>(0o377, base: 8)
"0o377".octal // == Radix<Int>(255, base: 8)?
255.hex // == Radix<Int>(0xFF, base: 16)
"0xFF".hex // == Radix<Int>(255, base: 16)?
255.radix(base: 5) // == Radix<Int>(255, base: 5)
"2010".radix(base: 5) // == Radix<Int>(255, base: 5)?
在下面的 README 中,你将看到结合使用这些功能是多么强大且优雅。
代理构造函数
两种调用方式,产生相同的结果。
// proxy constructor function
Hex(123) // Radix<Int>(123, base: 16)
// functional category property
123.hex // Radix<Int>(123, base: 16)
可以使用的任何 BinaryInteger
类型。
Int(123).hex // Radix<Int>(123)
Int8(123).hex // Radix<Int8>(123)
UInt8(123).hex // Radix<UInt8>(123)
Int16(123).hex // Radix<Int16>(123)
UInt16(123).hex // Radix<UInt16>(123)
Int32(123).hex // Radix<Int32>(123)
UInt32(123).hex // Radix<UInt32>(123)
Int64(123).hex // Radix<Int64>(123)
UInt64(123).hex // Radix<UInt64>(123)
有效的十六进制字符串可以使用,可以选择带有前缀 0x
或不带有前缀。
由于如果字符串不是有效的十六进制,则构造函数会失败并返回 nil
,因此该构造函数返回 Optional
。
如果没有指定整型类型,则默认为 Int
类型。
Hex("FF") // Radix<Int>(255)?
"FF".hex // Radix<Int>(255)?
"0xFF".hex // Radix<Int>(255)?
"ZZZZ".hex // nil ; not a valid hex string
要指定与 Int
不同的整型类型,请使用 as:
指定。
Hex("FF", as: UInt8.self) // Radix<UInt8>(255)?
"FF".hex(as: UInt8.self) // Radix<UInt8>(255)?
Hex("FFFFFF", as: UInt8.self) // nil -- 0xFFFFFF does not fit in UInt8, so init fails
"FFFFFF".hex(as: UInt8.self) // nil -- 0xFFFFFF does not fit in UInt8, so init fails
获取和设置值
各种方法都可用
let h = 255.hex // Radix<Int>(255)
h.value // Int(255)
h.stringValue // "FF"
h.stringValue(prefix: true) // "0xFF"
h.stringValue = "7F" // can also set the hex String and get value...
h.value // 127, type Int
如果需要统一的字符串格式化,可以指定前导0的个数
0xF.hex.stringValue // "F"
0xF.hex.stringValue(padTo: 2) // "0F"
0xF.hex.stringValue(padTo: 3) // "00F"
0xFFFF.hex.stringValue(padTo: 3) // "FFFF" - has no effect; it's > 3 places
也可以将前导0填充到每个数字位置的第n倍数
0xF.hex.stringValue(padToEvery: 2) // "0F"
0xFF.hex.stringValue(padToEvery: 2) // "FF"
0xFFF.hex.stringValue(padToEvery: 2) // "0FFF"
0xFFFF.hex.stringValue(padToEvery: 2) // "FFFF"
0x1.hex.stringValue(padToEvery: 4) // "0001"
0x12345.hex.stringValue(padToEvery: 4) // "00012345"
除了填充外,字符串还可以在每个第n个数字位置处分割,也可以与填充结合使用。
0xF.hex.stringValue(padTo: 8, splitEvery: 4) // "0000 000F"
0x123AB.hex.stringValue(padToEvery: 2, splitEvery: 2) // "01 23 AB"
等价性
可以使用典型运算符(==
、!=
、>
、<
)直接对Radix<T>
进行等价性测试,无需访问.value
属性。这使得语法更简洁、更方便。
let h1 = 10.hex // Radix<Int>
let h2 = 20.hex // Radix<Int>
h1.value == h2.value // this works but it's easier to just do this...
h1 == h2 // false
它们可以非常灵活地进行比较——甚至可以直接在不同的整数类型之间进行比较,无需进行类型转换。
let h1 = 10.hex // Radix<Int>
let h2 = 20.hex // Radix<Int>
h1 == h2 // false (comparing Radix<Int> with Radix<Int>)
h1 > 20 // true (comparing Radix<Int> with Int)
h1 != UInt8(20) // true (comparing Radix<Int> with UInt8)
// even though "FF".hex produces an Optional,
// the comparison still works safely without requiring the optional to be unwrapped first
"FF".hex == 255 // true
"FF".hex == 255.hex // true
"ZZ".hex == 255.hex // false - optional is nil
其他运算符
其他运算符同样得到支持,允许像等价性那样混合类型
+=
,-=
,*=
,/=
,<<
,>>
,&
位移动运算
直接在Radix
上可以用传统的二进制左/右位移
0b0100.hex << 1 // 0b1000
0b0100.hex >> 1 // 0b0010
数组和数据处理扩展
[二进整数]
任何整数数组都可以转换为等价的 [Radix
<T>]
数组
let a = [1, 2].hex // [Radix<Int>(1), Radix<Int>(2)]
let arr: [UInt8] = [3, 4]
let b = arr.hex // [Radix<UInt8>(3), Radix<UInt8>(4)]
// and back again:
a.values // [1, 2] of type [Int]
b.values // [3, 4] of type [UInt8]
它还可以展开为连接的 String
或 String
数组。
[0, 255, 0, 255].hex.stringValue // "00 FF 00 FF"
[0, 255, 0, 255].hex.stringValue(prefix: true) // "0x00 0xFF 0x00 0xFF"
[0, 255, 0, 255].hex.stringValues // ["00", "FF", "00", "FF"]
[0, 255, 0, 255].hex.stringValues(prefix: true) // ["0x00", "0xFF", "0x00", "0xFF"]
[String]
String
数组也可以转换为 Radix
<T>? 数组。`.values` 属性产生一个未展开的 [Optional
<T>]
数组。
["00", "0xFF", "ZZ"].hex.values // [Optional(0), Optional(255), nil]
它还可以轻松生成一个符合条件的 Swift 源数组字面量。
let arr = [0, 2, 255]
arr.hex.stringValueArrayLiteral // "[0x0, 0x2, 0xFF]"
arr.binary.stringValueArrayLiteral // "[0b0, 0b10, 0b11111111]"
Data
当将二进制数据输出到控制台或以易于阅读的格式呈现时非常有用。
let d = Data([0x1, 0x2, 0x3, 0xFF])
d.hex.stringValue(padTo: 2) // "01 02 03 FF"
值和内存访问方法
读取和操作基础整数值的附加方法。
位
.bit(Int)
[bit: Int] { get set }
- 获取指定位置(从右到左)的单独位值
- 索引属性也可用于获取或设置位值
- 基数无关
var h = 0b1100.binary
h.bit(0) // 0b0.binary
h.bit(2) // 0b1.binary
h[bit: 0] // 0b0 (type T, which is Int in this case)
h[bit: 2] // 0b1 (type T, which is Int in this case)
h[bit: 2] = 0b0
h.value // == 0b1000
半字节
.nibble(Int)
[nibble: Int] { get set }
- 获取指定位置(从右到左)的半字节(4位)值
- 索引属性也可用于获取或设置半字节值
- 基数无关
var h = 0x1234.hex
h.nibble(0) // 0x4.hex
h.nibble(3) // 0x1.hex
h[nibble: 0] // 0x4 (type T, which is Int in this case)
h[nibble: 3] // 0x1 (type T, which is Int in this case)
h[nibble: 3] = 0xF
h.value // == 0xF234
字节数
.bytes
- 一个便捷属性,用于返回值的原始字节数据,形式为数组[UInt8],基于系统字节序。
- 基数无关
let bytes = 0xFF00.hex.bytes
bytes // [0x00, 0xFF]
作者
由一系列
许可证
版权协议为 MIT 协议。详情请见 LICENSE。
该库以前被称为 SwiftHex。
贡献
欢迎贡献。欢迎发布 Issue 进行讨论。