如何从 Swift 中的 UInt8 变量中取出 N 位?
How to take N bits from a UInt8 variable in Swift?
我正在自学 Swift 尝试为应用程序实现 Base32 解码,但我似乎无法弄清楚如何在这种语言中低于字节级别。如果我可以将 UInt8 截断为 5 位并将其附加到我可以使用的 Data 对象,那将会很方便。
我在Python中写了这个函数:
def base32_decode(secret):
b32alphabet = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")
b32v = [b32alphabet.index(x) for x in secret if x != '=']
t1 = ["{0:0>5}".format(bin(v)[2:]) for v in b32v]
t2 = ''.join(t1)
t3 = textwrap.wrap(t2,8)
t4 = [int(v, 2) for v in t3 if len(v) == 8]
t5 = ''.join(["{0:0>2}".format(hex(v)[2:]) for v in t4])
它用于输出 base32 中数据的十六进制表示。我想在 Swift 中复制它(尽管不是转换为十六进制的部分)。然而,我做到了这一点:
func base32decode(string: String) -> Data
{
let b32a: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "2", "3", "4", "5", "6", "7"]
let complete: NSMutableData = NSMutableData()
var b32v: Array<UInt8> = []
for c in string.characters
{
let index = b32a.index(of: String(c))!
b32v.append(UInt8(index)) // Need to append only the 5 LSB
}
// Return b32v as base 32 decoded data
...
有没有简单的方法来做到这一点?我无法通过 Google.
找到任何内容
Swift 具有位操作运算符(|
、&
、<<
、>>
),其中
可用于提取字节的一部分(以及是否
"an easy way"与否当然是基于意见)。
您的 Python 代码显然首先创建了一个包含所有二进制数字的字符串,
然后将其分成 8 位的部分并转换为
十六进制值。
以下是不使用的可能实现
一个中间字符串。相反,解码位被累积
在一个整数中,一旦收集到 8 位,这些就是
附加到结果数组。
func base32decode(string: String) -> Data {
let b32a = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".characters)
var b32v: [UInt8] = []
var accum = 0
var bits = 0 // # of valid bits in `accum`
for c in string.characters {
if let index = b32a.index(of: c) {
accum = (accum << 5) | index
bits += 5
if bits >= 8 {
b32v.append(UInt8(truncatingBitPattern: accum >> (bits - 8)))
bits -= 8
}
}
}
return Data(bytes: b32v)
}
示例:
print(base32decode(string: "JBSWY3DPEB3W64TMMQQQ") as NSData)
// <48656c6c 6f20776f 726c6421>
(即 "Hello World!")。
该函数中有趣的部分是
accum = (accum << 5) | index
将 accum
中的所有位向左移动 5 个位置,并且
将最低 5 位设置为 index
,并且
b32v.append(UInt8(truncatingBitPattern: accum >> (bits - 8)))
将 accum
中最左边的 8 个有效位附加到数组。
我正在自学 Swift 尝试为应用程序实现 Base32 解码,但我似乎无法弄清楚如何在这种语言中低于字节级别。如果我可以将 UInt8 截断为 5 位并将其附加到我可以使用的 Data 对象,那将会很方便。
我在Python中写了这个函数:
def base32_decode(secret):
b32alphabet = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567")
b32v = [b32alphabet.index(x) for x in secret if x != '=']
t1 = ["{0:0>5}".format(bin(v)[2:]) for v in b32v]
t2 = ''.join(t1)
t3 = textwrap.wrap(t2,8)
t4 = [int(v, 2) for v in t3 if len(v) == 8]
t5 = ''.join(["{0:0>2}".format(hex(v)[2:]) for v in t4])
它用于输出 base32 中数据的十六进制表示。我想在 Swift 中复制它(尽管不是转换为十六进制的部分)。然而,我做到了这一点:
func base32decode(string: String) -> Data
{
let b32a: Array = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "2", "3", "4", "5", "6", "7"]
let complete: NSMutableData = NSMutableData()
var b32v: Array<UInt8> = []
for c in string.characters
{
let index = b32a.index(of: String(c))!
b32v.append(UInt8(index)) // Need to append only the 5 LSB
}
// Return b32v as base 32 decoded data
...
有没有简单的方法来做到这一点?我无法通过 Google.
找到任何内容Swift 具有位操作运算符(|
、&
、<<
、>>
),其中
可用于提取字节的一部分(以及是否
"an easy way"与否当然是基于意见)。
您的 Python 代码显然首先创建了一个包含所有二进制数字的字符串, 然后将其分成 8 位的部分并转换为 十六进制值。
以下是不使用的可能实现 一个中间字符串。相反,解码位被累积 在一个整数中,一旦收集到 8 位,这些就是 附加到结果数组。
func base32decode(string: String) -> Data {
let b32a = Array("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567".characters)
var b32v: [UInt8] = []
var accum = 0
var bits = 0 // # of valid bits in `accum`
for c in string.characters {
if let index = b32a.index(of: c) {
accum = (accum << 5) | index
bits += 5
if bits >= 8 {
b32v.append(UInt8(truncatingBitPattern: accum >> (bits - 8)))
bits -= 8
}
}
}
return Data(bytes: b32v)
}
示例:
print(base32decode(string: "JBSWY3DPEB3W64TMMQQQ") as NSData)
// <48656c6c 6f20776f 726c6421>
(即 "Hello World!")。
该函数中有趣的部分是
accum = (accum << 5) | index
将 accum
中的所有位向左移动 5 个位置,并且
将最低 5 位设置为 index
,并且
b32v.append(UInt8(truncatingBitPattern: accum >> (bits - 8)))
将 accum
中最左边的 8 个有效位附加到数组。