【问题标题】:Swift convert decimal String to UInt8-ArraySwift 将十进制字符串转换为 UInt8-Array
【发布时间】:2015-08-26 01:31:59
【问题描述】:

我有一个很长的字符串(600 多个字符),其中包含一个很大的十进制值(是的,我知道 - 听起来像一个 BigInteger)并且需要这个值的字节表示。

有没有什么简单的方法可以用 swift 存档?

static func decimalStringToUInt8Array(decimalString:String) -> [UInt8] {
  ...
}

【问题讨论】:

  • Swift(或 Foundation)没有处理大整数的库,但请参阅 stackoverflow.com/questions/25531914/…
  • 我看到了那些库,但它们都不兼容当前的 swift,并且允许在 unit8-array 之间进行转换
  • 嗯,你的问题的答案“有什么简单的方法可以用 swift 存档吗?” 就是 “不,没有”我>。 – Swift 不提供此功能,因此您必须编写自己的代码或使用第三方库。随着 Swift 的不断变化,任何第三方代码可能都必须适应。

标签: ios swift type-conversion


【解决方案1】:

编辑:针对 Swift 5 更新

我给你写了一个函数来转换你的数字字符串。这是用 Swift 5(最初是 Swift 1.2)编写的。

func decimalStringToUInt8Array(_ decimalString: String) -> [UInt8] {

    // Convert input string into array of Int digits
    let digits = Array(decimalString).compactMap { Int(String($0)) }

    // Nothing to process? Return an empty array.
    guard digits.count > 0 else { return [] }

    let numdigits = digits.count

    // Array to hold the result, in reverse order
    var bytes = [UInt8]()

    // Convert array of digits into array of Int values each
    // representing 6 digits of the original number.  Six digits
    // was chosen to work on 32-bit and 64-bit systems.
    // Compute length of first number.  It will be less than 6 if
    // there isn't a multiple of 6 digits in the number.
    var ints = Array(repeating: 0, count: (numdigits + 5)/6)
    var rem = numdigits % 6
    if rem == 0 {
        rem = 6
    }
    var index = 0
    var accum = 0
    for digit in digits {
        accum = accum * 10 + digit
        rem -= 1
        if rem == 0 {
            rem = 6
            ints[index] = accum
            index += 1
            accum = 0
        }
    }

    // Repeatedly divide value by 256, accumulating the remainders.
    // Repeat until original number is zero
    while ints.count > 0 {
        var carry = 0
        for (index, value) in ints.enumerated() {
            var total = carry * 1000000 + value
            carry = total % 256
            total /= 256
            ints[index] = total
        }

        bytes.append(UInt8(truncatingIfNeeded: carry))

        // Remove leading Ints that have become zero.
        while ints.count > 0 && ints[0] == 0 {
            ints.remove(at: 0)
        }
    }

    // Reverse the array and return it
    return bytes.reversed()
}

print(decimalStringToUInt8Array("0"))         // prints "[0]"
print(decimalStringToUInt8Array("255"))       // prints "[255]"
print(decimalStringToUInt8Array("256"))       // prints "[1,0]"
print(decimalStringToUInt8Array("1024"))      // prints "[4,0]"
print(decimalStringToUInt8Array("16777216"))  // prints "[1,0,0,0]"

这是反向功能。你会注意到它非常相似:

func uInt8ArrayToDecimalString(_ uint8array: [UInt8]) -> String {

    // Nothing to process? Return an empty string.
    guard uint8array.count > 0 else { return "" }

    // For efficiency in calculation, combine 3 bytes into one Int.
    let numvalues = uint8array.count
    var ints = Array(repeating: 0, count: (numvalues + 2)/3)
    var rem = numvalues % 3
    if rem == 0 {
        rem = 3
    }
    var index = 0
    var accum = 0
    for value in uint8array {
        accum = accum * 256 + Int(value)
        rem -= 1
        if rem == 0 {
            rem = 3
            ints[index] = accum
            index += 1
            accum = 0
        }
    }

    // Array to hold the result, in reverse order
    var digits = [Int]()

    // Repeatedly divide value by 10, accumulating the remainders.
    // Repeat until original number is zero
    while ints.count > 0 {
        var carry = 0
        for (index, value) in ints.enumerated() {
            var total = carry * 256 * 256 * 256 + value
            carry = total % 10
            total /= 10
            ints[index] = total
        }

        digits.append(carry)

        // Remove leading Ints that have become zero.
        while ints.count > 0 && ints[0] == 0 {
            ints.remove(at: 0)
        }
    }

    // Reverse the digits array, convert them to String, and join them
    return digits.reversed().map(String.init).joined()
}

进行往返测试以确保我们回到起点:

let a = "1234567890987654321333555777999888666444222000111"
let b = decimalStringToUInt8Array(a)
let c = uInt8ArrayToDecimalString(b)
if a == c {
    print("success")
} else {
    print("failure")
}
success

检查八个255 字节是否与UInt64.max 相同:

print(uInt8ArrayToDecimalString([255, 255, 255, 255, 255, 255, 255, 255]))
print(UInt64.max)
18446744073709551615
18446744073709551615

【讨论】:

  • 这是 惊人的 !!!太感谢了!我们自己创建了一个方法,但是您的方法可以正常工作,我们的应用程序确认了结果.. 这真是太棒了,谢谢!我们还创建了一个方法来将此 uint8-array 转换回一个大字符串,但不知何故,它会在中间生成另一​​个字符串,其中包含您的方法。您是否有一种干净的方法将结果数组转换回大十进制字符串@vacawama?再次感谢您,这真的帮助了我们!
  • 我添加了反函数。
  • 太棒了,节省了我的一天! TYVM
【解决方案2】:

您可以使用NSData(int: Int, size: Int) 方法获取一个 Int 到 NSData,然后从 NSData 获取字节到一个数组:[UInt8]

一旦你知道了,唯一的事情就是知道你的数组的大小。达尔文在那里派上了用场powfunction。这是一个工作示例:

func stringToUInt8(string: String) -> [UInt8] { 
if let int = string.toInt() {

 let power: Float = 1.0 / 16
 let size = Int(floor(powf(Float(int), power)) + 1)

 let data = NSData(bytes: &int, length: size)

 var b = [UInt8](count: size, repeatedValue: 0)

 return data.getBytes(&b, length: size)
}
}

【讨论】:

    【解决方案3】:

    如果您在十进制字符串上实现了除法,您可以重复除以 256。第一个除法的提示是你的最低有效字节。

    这是一个在 C 中除以标量的示例(假设数字的长度存储在 A[0] 中并将结果写入同一个数组中):

    void div(int A[], int B)
    {
        int i, t = 0;
        for (i = A[0]; i > 0; i--, t %= B)
            A[i] = (t = t * 10 + A[i]) / B;
        for (; A[0] > 1 && !A[A[0]]; A[0]--);
    }
    

    【讨论】:

    • 我不确定我是否明白你在那里做什么,将这段代码转换为 swift 并不容易:-/
    【解决方案4】:

    你总是可以这样做的:

    let bytes = [UInt8](decimalString.utf8)
    

    如果你想要 UTF-8 字节。

    【讨论】:

    • 这给了我字符串的字节为 utf-8,但我需要它的值作为字节。例如:let decimalString = "123456789";其十六进制值为 0x75BCD15,二进制值为 ...0001 0101,这也应该是字节数组的第一个和第二个条目。
    • 啊!我的错,我不明白你所说的“大十进制值”是什么意思。
    猜你喜欢
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 1970-01-01
    相关资源
    最近更新 更多