简体   繁体   English

快速将十进制字符串转换为UInt8-Array

[英]Swift convert decimal String to UInt8-Array

I have a very long String (600+ characters) holding a big decimal value (yes I know - sounds like a BigInteger) and need the byte representation of this value. 我有一个非常长的String(600多个字符),其中包含一个大十进制值(是的,我知道-听起来像BigInteger),并且需要此值的字节表示形式。

Is there any easy way to archive this with swift? 有什么简单的方法可以迅速将其存档?

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

Edit: Updated for Swift 5 编辑:为Swift 5更新

I wrote you a function to convert your number string. 我给你写了一个函数来转换你的数字字符串。 This is written in Swift 5 (originally Swift 1.2). 这是用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]"

Here's the reverse function. 这是反向功能。 You'll notice it is very similar: 您会发现它非常相似:

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()
}

Doing a round trip test to make sure we get back to where we started: 做一次往返测试以确保我们回到开始的地方:

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

Check that eight 255 bytes is the same as UInt64.max : 检查八个255字节是否与UInt64.max相同:

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

You can use the NSData(int: Int, size: Int) method to get an Int to NSData, and then get the bytes from NSData to an array: [UInt8] . 您可以使用NSData(int: Int, size: Int)方法将一个Int转换为NSData,然后将字节从NSData转换为一个数组: [UInt8]

Once you know that, the only thing is to know the size of your array. 一旦知道了,唯一的事情就是知道数组的大小。 Darwin comes in handy there with the pow function. 达尔文(Darwin)具有pow功能,非常方便。 Here is a working example: 这是一个工作示例:

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)
}
}

You can always do: 您可以随时这样做:

let bytes = [UInt8](decimalString.utf8)

If you want the UTF-8 bytes. 如果要使用UTF-8字节。

Provided you had division implemented on your decimal string you could divide by 256 repeatedly. 如果您对十进制字符串实现了除法,则可以重复除以256。 The reminder of the first division is the your least significant byte. 第一次除法的提醒是您的最低有效字节。

Here's an example of division by a scalar in C (assumed the length of the number is stored in A[0] and writes the result in the same array): 这是一个用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]--);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM