如何从Swift中的UInt8变量中取N位?

时间:2016-09-30 17:55:55

标签: swift bit-manipulation swift3 base32

我正在尝试为应用程序实现Base32解码,因为我自学了Swift,但我似乎无法弄清楚如何在这种语言中低于字节级别。如果我可以将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中复制它(虽然不是转换为hex部分)。但是,我到目前为止:

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找到任何内容。

1 个答案:

答案 0 :(得分:4)

Swift有位操作符(|&<<>>) 可用于提取字节的一部分(以及是否为  &#34;一种简单的方式&#34;是不是以意见为基础。)

你的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>

(&#34; Hello World!&#34;)。

该功能中有趣的部分是

  accum = (accum << 5) | index

accum中的所有位向左移动5个位置 将最低5位设置为index

  b32v.append(UInt8(truncatingBitPattern: accum >> (bits - 8)))

accum中最左边的8个有效位追加到数组中。